Giter Site home page Giter Site logo

acpi's People

Contributors

00xc avatar 64 avatar a0lson avatar alnyan avatar andy-python-programmer avatar atul9 avatar bors[bot] avatar cmsd2 avatar dentosal avatar ethindp avatar freax13 avatar fslongjin avatar fuchsnj avatar gegy avatar isaacwoods avatar knapsac avatar kwshaw1 avatar mattfbacon avatar michaelmelanson avatar rcerc avatar restioson avatar rw-vanc avatar semiviral avatar sh4d1 avatar spartan2909 avatar toku-sa-n avatar tomaka avatar toothbrush7777777 avatar ytakano avatar ytvwld avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

acpi's Issues

More things must be `unsafe`

Quite a few methods that are currently safe should really be unsafe. For instance, AcpiHandler methods (I will attempt to address this as I wish to try streamline its api), and methods that map physical memory (perhaps, better safe than sorry).

Add test to make sure AmlContext remains Send + Sync

When we introduced native methods, AmlContext lost its Send + Sync, as methods weren't constrained to be thread-safe. This was fixed in #91 by requiring them to be, but it's unfortunate that this wasn't picked up before then (and so we have broken releases, which is fine per our semver commitments, but not great).

A test that makes sure that AmlContext is Send + Sync should be pretty easy and will trip CI if we make a change that breaks this in the future.

Support DefDataRegion

These are special op regions that actually point to an ACPI table in the RSDT/XSDT. I guess we'll need a method on the handler that asks the OS to retrieve a mapping to the ACPI table, and give us the address to construct a op region from.

  • Parse opcode
  • Create handler method to ask for ACPI table
  • Construct and insert an op region from that info

Cannot access to `Signature` type

Sorry if I missed something, but we cannot access to Signature type because the module sdt is private. Is it intentional? If so, how to use methods like AcpiTables::get_sdt which takes Signature value?

Parsing PREFIX_CHAR is unimplemented!()

I'm working on a kernel using the acpi and aml crates, and the tables generated by QEMU contain parent prefix paths, which currently cause a panic since handling PREFIX_CHAR in name_string() is unimplemented!() (name_object.rs 73:28). Right now this is keeping me from being able to do much of anything with acpi tables. I fiddled around with it a bit trying to find a workaround but I couldn't get it to parse successfully. If you aren't planning on implementing it soon, I'd appreciate having a way to ignore those entries and continue parsing, or something like that.

The acpi crate unmaps mappings that contain other mappings

The acpi crate while calling search_for_rsdp_bios will map 0xF5000 with a size of 0x1000 and then map 0xF5B20 with a size of 0x24 and immediately after unmap the first mapping causing the second mapping to be invalid and cause a page fault while reading

Add predefined objects to AML interpreter

The firmware is allowed to assume that certain objects exist, that must be provided by the OSPM:

  • \_GL - the global lock mutex
  • \_OS - the name of the OS (note that this shouldn't be set to your real OS's name, as many firmwares expect specific strings to work correctly)
  • \_OSI - Operating System Interface support. Allows the firmware to query whether the OS supports a feature or not.
  • \_REV - the revision of the ACPI spec that the AML interpreter supports. This should be set internally, and will probably have to be a lie until our supports gets better.

Ideas on better testing infrastructure

So far, the constructed_tables_tests seem like a large part of each PR, but afaik have provided little benefit (in that they've completely failed to catch any of the bugs we've hit so far). Despite the work that's gone into them, my vote is to remove them and, in the long run, replace them with two new types of test:

  1. Effectively build a tiny bare-bones OS (probably from Phil's first edition) that implements acpi. This could also serve as an example of how to use the library. This would then be automatically run on Travis on a headless QEMU to test against the SeaBIOS tables.
  2. Long term: test against a dump of ACPI tables from real hardware, built up as a community initiative (hopefully we get some volunteers :P). Afaik, this hasn't really been done before, but should make sure the library deals with common quirks of real hardware's implementations

cc @Sh4d1; thoughts?

Improve allocation behaviour of MADT parsing

One of the use-cases of the acpi crate (the part that parses the static tables) is to do the static table discovery early on in the boot process. However, the heap may be very simple when this happens (e.g. Pebble uses a simple bump allocator for the bootloader heap), and so it'd be good if we can avoid re-allocating and wasting space by ascertaining the size of the Vecs we dynamically allocate. The biggest culprit at the moment is in the parse_apic_model method, which adds entries to the vectors as it goes through the table entries.

We can avoid this behaviour by doing a pre-pass through the MADT, counting the number of local APICs (n - 1 is then also the number of APs we'll have), and I/O APICS, then reserveing enough space in the Vecs.

Remove old testcase code

In the old testing infrastructure, we had code to construct "test-cases", such as this. We don't need these any more and so it'd be nice to strip them out.

make the Fadt public

Right now the acpi crate doesn't expose the Fadt table and instead picks some information from it, but somethings that are necessary for the operation of the acpi cannot be gathered without the user redefining the Fadt themselves.

I have a local copy of the repository with some Fadt fields public and re exporting it as public, if it's of interest i can make a PR with it.

Allow aml_tester to report test outcome using DefFatal

DefFatal can be used by ASL to report a fatal error to OSPM. We can use this to test features of ASL within asl_tester.

  • Don't panic, but mark test as failing, if DefFatal is encountered
  • Allow annotation from test to signal that a DefFatal is expected, so we can test it
  • Add a test for DefFatal to make sure it's parsed and handled correctly

AML Context Lookup

The documentation states that we can use something like

let my_aml_value = aml_context.lookup(&AmlName::from_str("\\_SB.PCI0.S08._ADR").unwrap());

to retrieve aml values, but when used, the compiler cannot find the method:

let result = context.lookup(&AmlName::from_str("\\_SB.PCI0.I2C0.TPDE").unwrap());
                     ^^^^^^ method not found in `AmlContext`

Is this method already implemented? If it is, are there other steps needed than calling AmlContext::new, parsing a table and calling lookup?

Page fault when put into practice

I've pulled in this library and when I put it into practice it page faults. Here's my code:

use crate::memory::{allocate_phys_range, free_range};
use crate::printkln;
use acpi::*;
use core::ptr::NonNull;

#[repr(C)]
#[derive(Clone, Copy, Default, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
struct AcpiMapper;

impl handler::AcpiHandler for AcpiMapper {
    unsafe fn map_physical_region<T>(
        &mut self,
        physical_address: usize,
        size: usize,
    ) -> handler::PhysicalMapping<T> {
        allocate_phys_range(
            physical_address as u64,
            (physical_address + region_size) as u64,
        );
        handler::PhysicalMapping {
            physical_start: physical_address,
            virtual_start: NonNull::new(physical_address as *mut T).unwrap(),
            region_length: size,
            mapped_length: size,
        }
    }

    fn unmap_physical_region<T>(&mut self, region: PhysicalMapping<T>) {
        free_range(
            region.physical_start as u64,
            (region.physical_start + region.mapped_length) as u64,
        );
    }
}

pub fn init() -> Option<Acpi> {
    let mut h = AcpiMapper::default();
    printkln!("init: Searching for ACPI tables");
    let table = match unsafe { search_for_rsdp_bios(&mut h) } {
        Ok(a) => a,
        Err(e) => {
            printkln!("init: ACPI table not found: {:?}", e);
            return None;
        }
    };
    printkln!("init: acpi rev. {} found", table.acpi_revision);
    Some(table)
}

When put into practice, this page faults when trying to read memory address F59CFh (which is a 36-byte memory allocation instead of the usual 4096-byte ones that this lib does). Is there a particular way of writing the ACPI memory handler? There was no documentation on actually writing a handler, nor are there any tests or examples.
Edit: I've figured out how this works; will update this issue if I fail. (My code had some errors in it, sorry about that.)

Parse the FADT

One of the first tables we should be able to parse is the FADT (and it's one of the easier ones), which tells us about register blocks for power management.

We should:

  1. Create a struct to represent the structure in Rust. It needs to be #[repr(C, packed)] and needs to match the layout the hardware has constructed. Either look at the relevant section of the spec or this helpful page to start
  2. Create a function parse_fadt(mapping : PhysicalMapping<Fadt>). This should validate and then parse the table.
  3. Work out which fields to use for the FACS and DSDT addresses, once again there's helpful info here
  4. Dispatch to parse_fadt in dispatch_sdt

There might be more info we care about from the FADT in the future, but this is probably a good start.

Support external objects

AML provides a mechanism to declare that an object exists, but is not defined in this table. This is generally used for objects that are defined in an SSDT, so parsing can continue until they're parsed. However, it's mainly useful for ASL compilers and decompilers - I'm not sure we ever need to act on it (but shouldn't crash if we get one).

  • Parse DefExternal
  • Work out if we need to record them

Documentation

I think it'd be nice to add some docs to the tables and their fields. We could use some docs from flower (I wrote a bit while figuring out ACPI for myself). For instance, the FADT code is very difficult to understand because it has loooooots of fields with no docs (side note, perhaps grouped fields could be put together into structs for readability).

MCFG parsing: entry length assertion failed

While parsing the MCFG table, the entry length assertion fails on one of my test devices (Dell Inspiron 1420 laptop).

An MCFG entry looks like it's supposed to be 16 bytes long. My test device reports a length of 62 bytes for the MCFG table, and after subtracting the header (36 bytes) + reserved area (8 bytes) that leaves exactly 18 bytes left, instead of the expected 16, so the assertion fails. The only thing odd I noticed is that the revision is 16 (my other test device that works correctly is revision 1). It looks like the data is valid if you only parse the first 16, so it might be good to remove the assertion and just let it round down. I couldn't find any documentation for that specific version.

Here is the raw entry data if that helps at all (in base 10)
[0,0,0,244,0,0,0,0,0,0,0,63,0,0,0,0,0,0]

Example with x86_64 crate?

Hello!

I tried to use this library but miserably failed to do so while battling with the rust compiler.
Could you add a little example while using the x86_64 crates FrameAllocator & OffsetPageTable?
I would deeply appreciate it :)
I tried using a struct like this:

#[derive(Clone)]
pub struct MyAcpiHandler<'a> {
    mapper: Rc<RefCell<&'a mut OffsetPageTable<'a>>>,
    frame_allocator: Rc<RefCell<&'a mut dyn FrameAllocator<Size4KiB>>>,
}

but this failed with the error:

.map_to(page, frame, flags, self.frame_allocator.get_mut())
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FrameAllocator<Size4KiB>` is not implemented for `&mut dyn FrameAllocator<Size4KiB>`

working together better with redox

Hi, I have been working on redox for a bit, and I came across your library. We can't utilize your lib for ACPI handling because the data is accessed in a very different way on redox. Basically, redox exposes the ACPI tables in as a file. For example, an MCFG might be exposed as the file "acpi:/tables/MCFG-424f43485320-425850434d434647". However, the acpi crate takes physical memory location. I would love to see the acpi somehow support this use case so that we could take advantage of this work.

Do you have any ideas of how this might be achieved?

I'd be happy to submit some patches if I can figure out a way to do it.

Thanks for any help!

Provide way to easily dump host's ACPI tables

On Linux, it looks like the kernel provides the raw ACPI table data in the sys filesystem at the paths: /sys/firmware/acpi/tables/{SIGNATURE (e.g. MCFG)}. This should make it fairly easy on Linux to get all the tables a platform has. Similar mechanisms might be present on Windows, if we want to extend to supporting that.

We also want to collect information about the platform, such as CPU model (maybe just the entire output of lshw?). We should give user's a chance to easily check what info they'd be contributing, to make it easy for people to make sure no sensitive data ends up in our test suite.

We then want to construct an entry in whatever format the integration tests end up in, allowing the test runner to test a wide variety of hardware. This makes it easy to contributors to simply dump their platform's tables, commit to their fork, and then make a pull-request.

Both reading from the /sys filesystem and running lshw need root access, so this would
unfortunately have to be run with sudo. Hopefully that wouldn't put too many people off, and they can always vet the code of the dumper themselves.

Move to better representation of namespace

When #47 lands, the AML namespace will move to being represented by two structures: a BTreeMap that maps handles to values, and another BTreeMap that maps names to handles. This second map is pretty inefficient (but no more than the current representation), because it stores the entire AmlName of every single object.

The representation can be improved by moving to a hand-rolled tree-like structure of name segments, and then the values and child scopes that are at each node. For large namespaces, this will reduce the memory consumption of the namespace by a fair amount, and also reduce the number of small heap allocations (as the name segments are fixed-size and so can be stored within the structure). It may also make searching the namespace for a specific path more efficient.

Support buffer fields

Buffer fields create AML values that read from and write to sections of buffers.

  • DefCreateBitField
  • DefCreateByteField
  • DefCreateWordField
  • DefCreateDWordField
  • DefCreateQWordField
  • DefCreateField
  • Handle reads from buffer fields
  • Handle writes to buffer fields

Parse AML using a PEG

So, right now I understand that AML is parsed using parser combinators. My understanding is that this also requires a number of hacks to get around Rusts language limitations (which may not exist in future but do exist as of now). I'm just curious, then, why parser combinators were chosen over a PEG?

I ask because I feel like the AML parser would be a lot easier to write using a PEG crate like peg. As an example, take the data object encoding as defined in SEC. 20.2.3:

Grammar:

    ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String | ConstObj | RevisionOp | DefBuffer

    DataObject := ComputationalData | DefPackage | DefVarPackage

    DataRefObject := DataObject | ObjectReference

    ByteConst := BytePrefix ByteData

    BytePrefix := 0x0A

    WordConst := WordPrefix WordData

    WordPrefix := 0x0B

    DWordConst := DWordPrefix DWordData

    DWordPrefix := 0x0C

    QWordConst := QWordPrefix QWordData

    QWordPrefix := 0x0E

    String := StringPrefix AsciiCharList NullChar

    StringPrefix := 0x0D

    ConstObj := ZeroOp | OneOp | OnesOp

    ByteList := Nothing | <bytedata bytelist>

    ByteData := 0x00 - 0xFF

    WordData := ByteData[0:7] ByteData[8:15]

        // 0x0000-0xFFFF

    DWordData := WordData[0:15] WordData[16:31]

        // 0x00000000-0xFFFFFFFF

    QWordData := DWordData[0:31] DWordData[32:63]

        // 0x0000000000000000-0xFFFFFFFFFFFFFFFF

    AsciiCharList := Nothing | <asciichar asciicharlist>

    AsciiChar := 0x01 - 0x7F

    NullChar := 0x00

    ZeroOp := 0x00

    OneOp := 0x01

    OnesOp := 0xFF

    RevisionOp := ExtOpPrefix 0x30

Using a PEG (like rust-peg and the peg::parser! macro), this could be transformed into something like:

peg::parser! {
grammar aml() for [u8] {
rule CompData() -> ComputationalData =
data:ByteConst
/ WordConst
/ DWordConst
/ QWordConst
/ String
/ ConstObj
/ RevisionOp
/ DefBuffer {? // parsing code... }

pub rule DataObject() -> DataObj =
CompData
/ DefPackage
/ DefVarPackage {? ... }

And so on and so forth. This isn't a fully flushed-out example, and I'd need to try to convert it into a fully-working parser, but the nice thing about this is that it almost identically follows the grammar notations defined in the AML reference and the macro will generate the parser for you. I'm not an expert on AML, but judging by section 20.2.1, AML begins with an AML table header:

    AMLCode := DefBlockHeader TermList

    DefBlockHeader :=
        TableSignature TableLength SpecCompliance CheckSum OemID OemTableID OemRevision CreatorID CreatorRevision

PEG-ified, this would look like:

///Top-level rule for AML, run all input through this rule
/// Return type can be anything that is defined like a normal Rust type
pub rule AmlCode() -> AmlAst =
code:DefBlockHeader TermList { ... }

rule DefBlockHeader() -> AmlBlockHeader =
block:TableSignature TableLength SpecCompliance CheckSum OemId OemTableId OemRevision CreatorId CreatorRevision { ... }

// ...

As noted in the peg crate documentation, anything within the {...} is normal Rust code, as illustrated by the example for parsing a DWord:

peg::parser!{
  grammar list_parser() for str {
    rule number() -> u32
      = n:$(['0'..='9']+) {? n.parse().or(Err("u32")) }

    pub rule list() -> Vec<u32>
      = "[" l:number() ** "," "]" { l }
  }
}

I don't know how the AML grammar would translate to the peg crate grammar notation, as I haven't tried my hand at it, but it seems (relatively) strateforward, and (perhaps) a lot easier than the current approach. But if its infeasible at this point, that's alright too -- I am primarily curious why this route wasn't chosen.

Parsing AML

Edit: this list is in the process of being replaced with dedicated issues for each feature.

Note: this list is probably still incomplete

Namespace modifiers

  • DefAlias (#93)
  • DefName
  • DefScope

Named objects

  • DefBankField
  • DefCreateBitField (#94)
  • DefCreateByteField (#94)
  • DefCreateDWordField (#94)
  • DefCreateField (#94)
  • DefCreateQWordField (#94)
  • DefCreateWordField (#94)
  • DefDataRegion (#95)
  • DefExternal (#96)
  • DefOpRegion
  • DefDevice
  • DefPowerRes (#97)
  • DefProcessor
  • DefThermalZone

Type 1 opcodes

  • DefBreak
  • DefBreakPoint
  • DefContinue
  • DefFatal
  • DefIfElse
  • DefLoad
  • DefLoadTable
  • DefNoop
  • DefNotify
  • DefRelease
  • DefReset
  • DefReturn
  • DefSignal
  • DefSleep
  • DefStall
  • DefUnload
  • DefWhile

Type 2 opcodes

  • DefAquire
  • DefAdd
  • DefAnd
  • DefBuffer
  • DefConcat
  • DefConcatRes
  • DefCondRefOp
  • DefCopyOpject
  • DefDecrement
  • DefDerefOf
  • DefDivide
  • DefFindSetLeftBit
  • DefFindSetRightBit
  • DefFromBDC
  • DefIncrement
  • DefIndex
  • DefLAnd
  • DefLEqual
  • DefLGreater
  • DefLGreaterEqual
  • DefLLess
  • DefLLessEqual
  • DefMid
  • DefLNot
  • DefLNotEqual
  • DefLoadTable
  • DefLOr
  • DefMatch
  • DefMod
  • DefMultiply
  • DefNAnd
  • DefNor
  • DefNot
  • DefObjectType
  • DefOr
  • DefPackage
  • DefVarPackage
  • DefShiftLeft
  • DefShiftRight
  • DefSizeOf
  • DefStore (yes to Names, Locals, and Argss. Not yet to Debug.)
  • DefSubtract
  • DefTimer
  • DefToBCD
  • DefToBuffer
  • DefToDecimalString
  • DefToHexString
  • DefToInteger
  • DefToString
  • DefWait
  • DefXor
  • MethodInvocation

Type 6 opcodes

  • DefRefOf
  • DefDerefOf
  • DefIndex
  • UserTermObj

Potential users: views on the API surface?

@Restioson and I have been discussing the API surface for acpi for a while over on Gitter and think it'd be useful to get some insight from more potential users.

So far, we have come up with two options for relaying information to the user:

  • Callbacks on AcpiHandler. This is a trait that allows the library to e.g. map physical memory into the virtual address space without knowing anything about the paging implementation, an implementation of which is provided by the user. This would be extended with methods such as register_processor which would be called as we parse the tables.
  • Return a struct Acpi (this currently exists but was meant to be internal to the library) that contains all the information gained from parsing the tables. This is likely to be large to keep around (for example, it will contain the entire AML namespace). This structure will also provide methods to interact with the ACPI context after parsing, such as executing control methods, changing global power state etc.

The key issue here is knowing how much information we want to provide, and in what format. I'm assuming most people won't care about the implementation details and don't want to read the ACPI spec, and so want a high-level overview that just allows them to get the information they need, but I would appreciate some feedback about this.

Writing this out, I am starting to strongly favour the second approach, as I believe it is more flexible from the perspective of the OS/user, but it'd be good to get some more opinions.

cc @rust-osdev/all

Provide function to get the preferred PM profile

This is meant as an easy first issue to get familiar with the library's workings. We should provide a way for the user to get the preferred Power Management profile from the FADT.

To do this, we should:

  1. Add an enum called PowerManagementProfile with the correct variants (read section 5.2.9 of the ACPI spec for a hint here)
  2. In parse_fadt, match against the preferred_pm_profile field of the FADT and turn it into a PowerManagementProfile
  3. Add a field preferred_pm_profile in the root Acpi struct and set it in parse_fadt
  4. Add a getter to Acpi to return this field

BIOS RSDP search: Allow start offset parameter?

It seems like there are sometimes both ACPI v1 and v2 RSDPs in memory: rust-osdev/bootloader#172 . Since we want to prioritize the v2 RSDP it would be great if the RSDP::search_for_on_bios function was able to return all available RSDPs, not just the first. This could be for example implemented by returning an Iterator from the function or by adding a start_offset parameter (perhaps in a separate function). Would you be open to a PR that implements something like this?

Interpret resource data types

This is the data in the buffers of _CRS, _PRS, and _SRS objects. There are many different byte encodings detailed in section 6.4 of the spec, which we should interpret and provide through a nice interface. We also want to be able to encode a set of settings provided by the library user back into the representation we can invoke a _SRS method with.

Roadmap

This is a tracking issue for getting acpi into a "vaguely useful" state. We should be able to parse most common ACPI tables and standard-conforming AML. I'd also like to get some testing infrastructure up and running pretty soon.

General

  • Land changes in multiboot2-elf64 to support RSDP/XSDT tags (multiboot2-elf64/#43)
  • Construct a RSDP given a physical address
  • Manually scan for the RSDP
  • Parse RSDT directly, given the address, for use with multiboot2 crate etc.
  • Infrastructure for asking the kernel to map physical memory etc.
  • Flesh out 'Using' section in Readme on how to actually use the library
  • Add support for logging with log

Tables we should be able to parse

  • RSDT
  • XSDT
  • FADT
  • MADT (#20) (full support for i8259 and APIC models, SAPIC, X2APIC and GIC not yet supported)
  • DSDT and SSDTs (#9, ...)
  • HPET (#16)

Parsing AML

  • Basic parsing stuff (#9)
  • Reliable error handling in case of invalid AML or unimplemented parsing routines (#9)
  • Be able to parse SeaBios' tables

Testing infrastructure

  • Simple OS running on headless QEMU to test SeaBios. Run on Travis.
  • Script to dump users' ACPI info (useful stuff) + /proc/cpuinfo?
  • The Great Acpi Dump
  • Set up test suite for running acpi against dumped tables
  • Add SeaBios dump to dump for QEMU and Bochs support
  • Test RSDP validation with individually valid/invalid RSDPs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.