Clone of chromium aad1ce808763f59c7a3753e08f1500a104ecc6fd refs/remotes/origin/HEAD
diff --git a/mojo/nacl/DEPS b/mojo/nacl/DEPS
new file mode 100644
index 0000000..69e7ada
--- /dev/null
+++ b/mojo/nacl/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+native_client/src/public",
+  "+native_client/src/trusted/desc",
+  "+native_client/src/trusted/service_runtime",
+]
diff --git a/mojo/nacl/README b/mojo/nacl/README
new file mode 100644
index 0000000..36913ac
--- /dev/null
+++ b/mojo/nacl/README
@@ -0,0 +1,24 @@
+This is a prototype for plumbing Mojo into the NaCl sandbox.  It is
+currently insecure (see below), does not provide a stable ABI (IRT
+support must be added), and does not support Mojo functions that
+return pointers (for example, MojoMapBuffer).
+
+generator/interface.py contains a programmatic description of the
+stable Mojo interface.  This will need to be updated as the interface
+changes.  Run generator/generate_nacl_bindings.py to generate the
+bindings that plumb this interface into the NaCl sandbox.
+
+To test: Build "monacl_shell" and "monacl_test".  Run monacl_shell
+with the IRT as the first argument and the monacl_test as the second
+argument.  For example, to run a Debug 32-bit Intel build:
+
+  cd out/Debug
+  ./monacl_shell irt_core_newlib_x32.nexe monacl_test_newlib_x32.nexe
+
+Security TODO list:
+  Separate trusted and untrusted Mojo handles.
+  Validate and copy option structures.
+  Protect untrusted buffers passed into Mojo:
+    NaClVmIoWillStart/HasEnded.
+    volatile accesses to untrusted memory (untrusted code could race).
+  Overflow checking in array bounds validation.
\ No newline at end of file
diff --git a/mojo/nacl/generator/generate_nacl_bindings.py b/mojo/nacl/generator/generate_nacl_bindings.py
new file mode 100755
index 0000000..2c8ae9d
--- /dev/null
+++ b/mojo/nacl/generator/generate_nacl_bindings.py
@@ -0,0 +1,404 @@
+#!/usr/bin/python
+# 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.
+
+# pylint: disable=W0104,W0106,F0401,R0201
+
+import optparse
+import os.path
+import sys
+
+import interface
+
+
+def _ScriptDir():
+  return os.path.dirname(os.path.abspath(__file__))
+
+
+def _GetDirAbove(dirname):
+  """Returns the directory "above" this file containing |dirname| (which must
+  also be "above" this file)."""
+  path = _ScriptDir()
+  while True:
+    path, tail = os.path.split(path)
+    assert tail
+    if tail == dirname:
+      return path
+
+
+def _AddThirdPartyImportPath():
+  sys.path.append(os.path.join(_GetDirAbove('mojo'), 'third_party'))
+
+
+_AddThirdPartyImportPath()
+import jinja2
+
+loader = jinja2.FileSystemLoader(_ScriptDir())
+jinja_env = jinja2.Environment(loader=loader, keep_trailing_newline=True)
+
+
+# Accumulate lines of code with varying levels of indentation.
+class CodeWriter(object):
+  def __init__(self):
+    self._lines = []
+    self._margin = ''
+    self._margin_stack = []
+
+  def __lshift__(self, line):
+    self._lines.append((self._margin + line).rstrip())
+
+  def PushMargin(self):
+    self._margin_stack.append(self._margin)
+    self._margin += '  '
+
+  def PopMargin(self):
+    self._margin = self._margin_stack.pop()
+
+  def GetValue(self):
+    return '\n'.join(self._lines).rstrip() + '\n'
+
+  def Indent(self):
+    return Indent(self)
+
+
+# Context handler that automatically indents and dedents a CodeWriter
+class Indent(object):
+  def __init__(self, writer):
+    self._writer = writer
+
+  def __enter__(self):
+    self._writer.PushMargin()
+
+  def __exit__(self, type_, value, traceback):
+    self._writer.PopMargin()
+
+
+def TemplateFile(name):
+  return os.path.join(os.path.dirname(__file__), name)
+
+
+# Wraps comma separated lists as needed.
+def Wrap(pre, items, post):
+  complete = pre + ', '.join(items) + post
+  if len(complete) <= 80:
+    return [complete]
+  lines = [pre]
+  indent = '    '
+  for i, item in enumerate(items):
+    if i < len(items) - 1:
+      lines.append(indent + item + ',')
+    else:
+      lines.append(indent + item + post)
+  return lines
+
+
+def GeneratorWarning():
+  return ('// WARNING this file was generated by %s\n// Do not edit by hand.' %
+          os.path.basename(__file__))
+
+
+# Untrusted library implementing the public Mojo API.
+def GenerateLibMojo(functions, out):
+  template = jinja_env.get_template('libmojo.cc.tmpl')
+
+  code = CodeWriter()
+
+  for f in functions:
+    for line in Wrap('%s %s(' % (f.return_type, f.name), f.ParamList(), ') {'):
+      code << line
+
+    # 2 extra parameters: message ID and return value.
+    num_params = len(f.params) + 2
+
+    with code.Indent():
+      code << 'uint32_t params[%d];' % num_params
+      return_type = f.result_param.base_type
+      if return_type == 'MojoResult':
+        default = 'MOJO_RESULT_INVALID_ARGUMENT'
+      elif return_type == 'MojoTimeTicks':
+        default = '0'
+      else:
+        raise Exception('Unhandled return type: ' + return_type)
+      code << '%s %s = %s;' % (return_type, f.result_param.name, default)
+
+      # Message ID
+      code << 'params[0] = %d;' % f.uid
+      # Parameter pointers
+      cast_template = 'params[%d] = reinterpret_cast<uint32_t>(%s);'
+      for p in f.params:
+        ptr = p.name
+        if p.IsPassedByValue():
+          ptr = '&' + ptr
+        code << cast_template % (p.uid + 1, ptr)
+      # Return value pointer
+      code << cast_template % (num_params - 1, '&' + f.result_param.name)
+
+      code << 'DoMojoCall(params, sizeof(params));'
+      code << 'return %s;' % f.result_param.name
+
+    code << '}'
+    code << ''
+
+  body = code.GetValue()
+  text = template.render(
+    generator_warning=GeneratorWarning(),
+    body=body)
+  out.write(text)
+
+
+# Parameters passed into trusted code are handled differently depending on
+# details of the parameter.  ParamImpl instances encapsulate these differences
+# and are used to generate the code that transfers parameters across the
+# untrusted/trusted boundary.
+class ParamImpl(object):
+  def __init__(self, param):
+    self.param = param
+
+  # Declare whatever variables are needed to handle this particular parameter.
+  def DeclareVars(self, code):
+    raise NotImplementedError()
+
+  # Convert the untrusted representation of the parameter into a trusted
+  # representation, such as a scalar value or a trusted pointer into the
+  # untrusted address space.
+  def ConvertParam(self):
+    raise NotImplementedError()
+
+  # For this particular parameter, what expression should be passed when
+  # invoking the trusted Mojo API function?
+  def CallParam(self):
+    raise NotImplementedError()
+
+  # After invoking the trusted Mojo API function, transfer data back into
+  # untrusted memory.  Overriden for Out and InOut parameters.
+  def CopyOut(self, code):
+    pass
+
+  # Converting array parameters needs to be defered until after the scalar
+  # parameter containing the size of the array has itself been converted.
+  def IsArray(self):
+    return False
+
+
+class ScalarInputImpl(ParamImpl):
+  def DeclareVars(self, code):
+    code << '%s %s_value;' % (self.param.base_type, self.param.name)
+
+  def ConvertParam(self):
+    p = self.param
+    return ('ConvertScalarInput(nap, params[%d], &%s_value)' %
+            (p.uid + 1, p.name))
+
+  def CallParam(self):
+    return '%s_value' % self.param.name
+
+
+class ScalarOutputImpl(ParamImpl):
+  def DeclareVars(self, code):
+    code << '%s volatile* %s_ptr;' % (self.param.base_type, self.param.name)
+    code << '%s %s_value;' % (self.param.base_type, self.param.name)
+
+  def ConvertParam(self):
+    p = self.param
+    return 'ConvertScalarOutput(nap, params[%d], &%s_ptr)' % (p.uid + 1, p.name)
+
+  def CallParam(self):
+    return '&%s_value' % self.param.name
+
+  def CopyOut(self, code):
+    name = self.param.name
+    code << '*%s_ptr = %s_value;' % (name, name)
+
+
+class ScalarInOutImpl(ParamImpl):
+  def DeclareVars(self, code):
+    code << '%s volatile* %s_ptr;' % (self.param.base_type, self.param.name)
+    code << '%s %s_value;' % (self.param.base_type, self.param.name)
+
+  def ConvertParam(self):
+    p = self.param
+    return ('ConvertScalarInOut(nap, params[%d], %s, &%s_value, &%s_ptr)' %
+            (p.uid + 1, CBool(p.is_optional), p.name, p.name))
+
+  def CallParam(self):
+    name = self.param.name
+    expr = '&%s_value' % name
+    if self.param.is_optional:
+      expr = '%s_ptr ? %s : NULL' % (name, expr)
+    return expr
+
+  def CopyOut(self, code):
+    name = self.param.name
+    if self.param.is_optional:
+      code << 'if (%s_ptr != NULL) {' % (name)
+      with code.Indent():
+        code << '*%s_ptr = %s_value;' % (name, name)
+      code << '}'
+    else:
+      code << '*%s_ptr = %s_value;' % (name, name)
+
+
+class ArrayImpl(ParamImpl):
+  def DeclareVars(self, code):
+    code << '%s %s;' % (self.param.param_type, self.param.name)
+
+  def ConvertParam(self):
+    p = self.param
+    if p.base_type == 'void':
+      element_size = '1'
+    else:
+      element_size = 'sizeof(*%s)' % p.name
+
+    return ('ConvertArray(nap, params[%d], %s, %s, %s, &%s)' %
+            (p.uid + 1, p.size + '_value', element_size, CBool(p.is_optional),
+             p.name))
+
+  def CallParam(self):
+    return self.param.name
+
+  def IsArray(self):
+    return True
+
+
+class StructInputImpl(ParamImpl):
+  def DeclareVars(self, code):
+    code << '%s %s;' % (self.param.param_type, self.param.name)
+
+  def ConvertParam(self):
+    p = self.param
+    return ('ConvertStruct(nap, params[%d], %s, &%s)' %
+            (p.uid + 1, CBool(p.is_optional), p.name))
+
+  def CallParam(self):
+    return self.param.name
+
+
+def ImplForParam(p):
+  if p.IsScalar():
+    if p.is_output:
+      if p.is_input:
+        return ScalarInOutImpl(p)
+      else:
+        return ScalarOutputImpl(p)
+    else:
+      return ScalarInputImpl(p)
+  elif p.is_array:
+    return ArrayImpl(p)
+  elif p.is_struct:
+    return StructInputImpl(p)
+  else:
+    assert False, p
+
+
+def CBool(value):
+  return 'true' if value else 'false'
+
+
+# A trusted wrapper that validates the arguments passed from untrusted code
+# before passing them to the underlying public Mojo API.
+def GenerateMojoSyscall(functions, out):
+  template = jinja_env.get_template('mojo_syscall.cc.tmpl')
+
+  code = CodeWriter()
+  code.PushMargin()
+
+  for f in functions:
+    impls = [ImplForParam(p) for p in f.params]
+    impls.append(ImplForParam(f.result_param))
+
+    code << 'case %d:' % f.uid
+
+    code.PushMargin()
+
+    code << '{'
+
+    with code.Indent():
+      num_params = len(f.params) + 2
+      code << 'if (num_params != %d) {' % num_params
+      with code.Indent():
+        code << 'return -1;'
+      code << '}'
+
+      # Declare temporaries.
+      for impl in impls:
+        impl.DeclareVars(code)
+
+      def ConvertParam(code, impl):
+        code << 'if (!%s) {' % impl.ConvertParam()
+        with code.Indent():
+          code << 'return -1;'
+        code << '}'
+
+      code << '{'
+      with code.Indent():
+        code << 'ScopedCopyLock copy_lock(nap);'
+        # Convert and validate pointers in two passes.
+        # Arrays cannot be validated until the size parameter has been
+        # converted.
+        for impl in impls:
+          if not impl.IsArray():
+            ConvertParam(code, impl)
+        for impl in impls:
+          if impl.IsArray():
+            ConvertParam(code, impl)
+      code << '}'
+      code << ''
+
+      # Call
+      getParams = [impl.CallParam() for impl in impls[:-1]]
+      code << 'result_value = %s(%s);' % (f.name, ', '.join(getParams))
+      code << ''
+
+      # Write outputs
+      code << '{'
+      with code.Indent():
+        code << 'ScopedCopyLock copy_lock(nap);'
+        for impl in impls:
+          impl.CopyOut(code)
+      code << '}'
+      code << ''
+
+      code << 'return 0;'
+    code << '}'
+
+    code.PopMargin()
+
+  body = code.GetValue()
+  text = template.render(
+    generator_warning=GeneratorWarning(),
+    body=body)
+  out.write(text)
+
+
+def OutFile(dir_path, name):
+  if not os.path.exists(dir_path):
+    os.makedirs(dir_path)
+  return open(os.path.join(dir_path, name), 'w')
+
+
+def main(args):
+  usage = 'usage: %prog [options]'
+  parser = optparse.OptionParser(usage=usage)
+  parser.add_option(
+      '-d',
+      dest='out_dir',
+      metavar='DIR',
+      help='output generated code into directory DIR')
+  options, args = parser.parse_args(args=args)
+  if not options.out_dir:
+    parser.error('-d is required')
+  if args:
+    parser.error('unexpected positional arguments: %s' % ' '.join(args))
+
+  mojo = interface.MakeInterface()
+
+  out = OutFile(options.out_dir, 'libmojo.cc')
+  GenerateLibMojo(mojo.functions, out)
+
+  out = OutFile(options.out_dir, 'mojo_syscall.cc')
+  GenerateMojoSyscall(mojo.functions, out)
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/mojo/nacl/generator/interface.py b/mojo/nacl/generator/interface.py
new file mode 100644
index 0000000..2a23fd7
--- /dev/null
+++ b/mojo/nacl/generator/interface.py
@@ -0,0 +1,108 @@
+# 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.
+
+# pylint: disable=F0401
+
+import interface_dsl
+
+def MakeInterface():
+  mojo = interface_dsl.Interface()
+
+  f = mojo.Func('MojoCreateSharedBuffer', 'MojoResult')
+  f.Param('options').InStruct('MojoCreateSharedBufferOptions').Optional()
+  f.Param('num_bytes').In('uint64_t')
+  f.Param('shared_buffer_handle').Out('MojoHandle')
+
+  f = mojo.Func('MojoDuplicateBufferHandle', 'MojoResult')
+  f.Param('buffer_handle').In('MojoHandle')
+  f.Param('options').InStruct('MojoDuplicateBufferHandleOptions').Optional()
+  f.Param('new_buffer_handle').Out('MojoHandle')
+
+  f = mojo.Func('MojoMapBuffer', 'MojoResult')
+  f.Param('buffer_handle').In('MojoHandle')
+  f.Param('offset').In('uint64_t')
+  f.Param('num_bytes').In('uint64_t')
+  f.Param('buffer').Out('void*')
+  f.Param('flags').In('MojoMapBufferFlags')
+
+  f = mojo.Func('MojoUnmapBuffer', 'MojoResult')
+  f.Param('buffer').In('void*')
+
+  f = mojo.Func('MojoCreateDataPipe', 'MojoResult')
+  f.Param('options').InStruct('MojoCreateDataPipeOptions').Optional()
+  f.Param('data_pipe_producer_handle').Out('MojoHandle')
+  f.Param('data_pipe_consumer_handle').Out('MojoHandle')
+
+  f = mojo.Func('MojoWriteData', 'MojoResult')
+  f.Param('data_pipe_producer_handle').In('MojoHandle')
+  f.Param('elements').InArray('void', 'num_bytes')
+  f.Param('num_bytes').InOut('uint32_t')
+  f.Param('flags').In('MojoWriteDataFlags')
+
+  f = mojo.Func('MojoBeginWriteData', 'MojoResult')
+  f.Param('data_pipe_producer_handle').In('MojoHandle')
+  f.Param('buffer').Out('void*')
+  f.Param('buffer_num_bytes').InOut('uint32_t')
+  f.Param('flags').In('MojoWriteDataFlags')
+
+  f = mojo.Func('MojoEndWriteData', 'MojoResult')
+  f.Param('data_pipe_producer_handle').In('MojoHandle')
+  f.Param('num_bytes_written').In('uint32_t')
+
+  f = mojo.Func('MojoReadData', 'MojoResult')
+  f.Param('data_pipe_consumer_handle').In('MojoHandle')
+  f.Param('elements').OutArray('void', 'num_bytes')
+  f.Param('num_bytes').InOut('uint32_t')
+  f.Param('flags').In('MojoReadDataFlags')
+
+  f = mojo.Func('MojoBeginReadData', 'MojoResult')
+  f.Param('data_pipe_consumer_handle').In('MojoHandle')
+  f.Param('buffer').Out('const void*')
+  f.Param('buffer_num_bytes').InOut('uint32_t')
+  f.Param('flags').In('MojoReadDataFlags')
+
+  f = mojo.Func('MojoEndReadData', 'MojoResult')
+  f.Param('data_pipe_consumer_handle').In('MojoHandle')
+  f.Param('num_bytes_read').In('uint32_t')
+
+  f = mojo.Func('MojoGetTimeTicksNow', 'MojoTimeTicks')
+
+  f = mojo.Func('MojoClose', 'MojoResult')
+  f.Param('handle').In('MojoHandle')
+
+  f = mojo.Func('MojoWait', 'MojoResult')
+  f.Param('handle').In('MojoHandle')
+  f.Param('signals').In('MojoHandleSignals')
+  f.Param('deadline').In('MojoDeadline')
+
+  f = mojo.Func('MojoWaitMany', 'MojoResult')
+  f.Param('handles').InArray('MojoHandle', 'num_handles')
+  f.Param('signals').InArray('MojoHandleSignals', 'num_handles')
+  f.Param('num_handles').In('uint32_t')
+  f.Param('deadline').In('MojoDeadline')
+
+  f = mojo.Func('MojoCreateMessagePipe', 'MojoResult')
+  f.Param('options').InStruct('MojoCreateMessagePipeOptions').Optional()
+  f.Param('message_pipe_handle0').Out('MojoHandle')
+  f.Param('message_pipe_handle1').Out('MojoHandle')
+
+  f = mojo.Func('MojoWriteMessage', 'MojoResult')
+  f.Param('message_pipe_handle').In('MojoHandle')
+  f.Param('bytes').InArray('void', 'num_bytes').Optional()
+  f.Param('num_bytes').In('uint32_t')
+  f.Param('handles').InArray('MojoHandle', 'num_handles').Optional()
+  f.Param('num_handles').In('uint32_t')
+  f.Param('flags').In('MojoWriteMessageFlags')
+
+  f = mojo.Func('MojoReadMessage', 'MojoResult')
+  f.Param('message_pipe_handle').In('MojoHandle')
+  f.Param('bytes').OutArray('void', 'num_bytes').Optional()
+  f.Param('num_bytes').InOut('uint32_t').Optional()
+  f.Param('handles').OutArray('MojoHandle', 'num_handles').Optional()
+  f.Param('num_handles').InOut('uint32_t').Optional()
+  f.Param('flags').In('MojoReadMessageFlags')
+
+  mojo.Finalize()
+
+  return mojo
diff --git a/mojo/nacl/generator/interface_dsl.py b/mojo/nacl/generator/interface_dsl.py
new file mode 100644
index 0000000..dfc85aa
--- /dev/null
+++ b/mojo/nacl/generator/interface_dsl.py
@@ -0,0 +1,116 @@
+# 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.
+
+class Interface(object):
+  def __init__(self):
+    self.functions = []
+
+  def Func(self, name, return_type):
+    f = Function(self, len(self.functions), name, return_type)
+    self.functions.append(f)
+    return f
+
+  def Finalize(self):
+    for f in self.functions:
+      f.Finalize()
+
+class Function(object):
+  def __init__(self, parent, uid, name, return_type):
+    self.parent = parent
+    self.uid = uid
+    self.name = name
+    self.return_type = return_type
+    self.params = []
+    self.param_by_name = {}
+    self.result_param = None
+
+  def Param(self, name, param_type=None):
+    p = Param(self, len(self.params), name, param_type)
+    self.params.append(p)
+    self.param_by_name[name] = p
+    return p
+
+  def ParamList(self):
+    return [param.param_type + ' ' + param.name for param in self.params]
+
+  def ParamDecl(self):
+    if self.params:
+      return ', '.join(self.ParamList())
+    else:
+      return 'void'
+
+  def Finalize(self):
+    self.result_param = Param(self, len(self.params), 'result')
+    self.result_param.Out(self.return_type)
+
+class Param(object):
+  def __init__(self, parent, uid, name, param_type=None):
+    self.parent = parent
+    self.uid = uid
+    self.name = name
+    self.base_type = param_type
+    self.param_type = param_type
+    self.size = None
+    self.is_input = False
+    self.is_output = False
+    self.is_array = False
+    self.is_struct = False
+    self.is_optional = False
+
+  def GetSizeParam(self):
+    assert self.size
+    return self.parent.param_by_name[self.size]
+
+  def In(self, ty):
+    self.base_type = ty
+    self.param_type = ty
+    self.is_input = True
+    return self
+
+  def InArray(self, ty, size):
+    self.base_type = ty
+    self.param_type = 'const ' + ty + '*'
+    self.size = size
+    self.is_input = True
+    self.is_array = True
+    return self
+
+  def InStruct(self, ty):
+    self.base_type = ty
+    self.param_type = 'const struct ' + ty + '*'
+    self.is_input = True
+    self.is_struct = True
+    return self
+
+  def InOut(self, ty):
+    self.base_type = ty
+    self.param_type = ty + '*'
+    self.is_input = True
+    self.is_output = True
+    return self
+
+  def Out(self, ty):
+    self.base_type = ty
+    self.param_type = ty + '*'
+    self.is_output = True
+    return self
+
+  def OutArray(self, ty, size):
+    self.base_type = ty
+    self.param_type = ty + '*'
+    self.size = size
+    self.is_array = True
+    self.is_output = True
+    return self
+
+  def Optional(self):
+    assert not self.IsPassedByValue()
+    self.is_optional = True
+    return self
+
+  def IsScalar(self):
+    return not self.is_array and not self.is_struct
+
+  def IsPassedByValue(self):
+    return not self.is_output and self.IsScalar()
diff --git a/mojo/nacl/generator/libmojo.cc.tmpl b/mojo/nacl/generator/libmojo.cc.tmpl
new file mode 100644
index 0000000..7690d82
--- /dev/null
+++ b/mojo/nacl/generator/libmojo.cc.tmpl
@@ -0,0 +1,25 @@
+// 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.
+
+{{generator_warning}}
+
+#include "mojo/public/c/system/core.h"
+#include "native_client/src/public/chrome_main.h"
+#include "native_client/src/public/imc_syscalls.h"
+#include "native_client/src/public/imc_types.h"
+
+#define NACL_MOJO_DESC (NACL_CHROME_DESC_BASE + 2)
+
+static void DoMojoCall(uint32_t params[], nacl_abi_size_t num_params) {
+  NaClAbiNaClImcMsgIoVec iov[1] = {
+    {params, num_params}
+  };
+  NaClAbiNaClImcMsgHdr msgh = {iov, 1, NULL, 0};
+  // Note: return value unchecked.  We're relying on the result parameter being
+  // unmodified - if the syscall fails, the Mojo function will return whatever
+  // the result parameter was initialized to before this function was called.
+  imc_sendmsg(NACL_MOJO_DESC, &msgh, 0);
+}
+
+{{body}}
diff --git a/mojo/nacl/generator/mojo_syscall.cc.tmpl b/mojo/nacl/generator/mojo_syscall.cc.tmpl
new file mode 100644
index 0000000..136e672
--- /dev/null
+++ b/mojo/nacl/generator/mojo_syscall.cc.tmpl
@@ -0,0 +1,66 @@
+// 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.
+
+{{generator_warning}}
+
+#include "mojo/nacl/mojo_syscall.h"
+
+#include <stdio.h>
+
+#include "mojo/nacl/mojo_syscall_internal.h"
+#include "mojo/public/c/system/core.h"
+#include "native_client/src/public/chrome_main.h"
+#include "native_client/src/public/nacl_app.h"
+#include "native_client/src/trusted/desc/nacl_desc_custom.h"
+
+namespace {
+
+void MojoDescDestroy(void* handle) {
+}
+
+ssize_t MojoDescSendMsg(void* handle,
+                        const struct NaClImcTypedMsgHdr* msg,
+                        int flags) {
+  struct NaClApp* nap = static_cast<struct NaClApp*>(handle);
+
+  if (msg->iov_length != 1 || msg->ndesc_length != 0) {
+    return -1;
+  }
+
+  uint32_t volatile* params = static_cast<uint32_t volatile*>(msg->iov[0].base);
+  size_t num_params = msg->iov[0].length / sizeof(*params);
+
+  if (num_params < 1) {
+    return -1;
+  }
+
+  uint32_t msg_type = params[0];
+  switch (msg_type) {
+{{body}}
+  }
+
+  return -1;
+}
+
+ssize_t MojoDescRecvMsg(void* handle,
+                        struct NaClImcTypedMsgHdr* msg,
+                        int flags) {
+  return -1;
+}
+
+struct NaClDesc* MakeMojoDesc(struct NaClApp* nap) {
+  struct NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER;
+  funcs.Destroy = MojoDescDestroy;
+  funcs.SendMsg = MojoDescSendMsg;
+  funcs.RecvMsg = MojoDescRecvMsg;
+  return NaClDescMakeCustomDesc(nap, &funcs);
+}
+
+} // namespace
+
+#define NACL_MOJO_DESC (NACL_CHROME_DESC_BASE + 2)
+
+void InjectMojo(struct NaClApp* nap) {
+  NaClAppSetDesc(nap, NACL_MOJO_DESC, MakeMojoDesc(nap));
+}
diff --git a/mojo/nacl/mojo_syscall.h b/mojo/nacl/mojo_syscall.h
new file mode 100644
index 0000000..f195769
--- /dev/null
+++ b/mojo/nacl/mojo_syscall.h
@@ -0,0 +1,10 @@
+// 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 MOJO_NACL_MOJO_SYSCALL_H_
+#define MOJO_NACL_MOJO_SYSCALL_H_
+
+void InjectMojo(struct NaClApp* nap);
+
+#endif // MOJO_NACL_MOJO_SYSCALL_H_
diff --git a/mojo/nacl/mojo_syscall_internal.h b/mojo/nacl/mojo_syscall_internal.h
new file mode 100644
index 0000000..f0795e6
--- /dev/null
+++ b/mojo/nacl/mojo_syscall_internal.h
@@ -0,0 +1,150 @@
+// 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 MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
+#define MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
+
+#include "native_client/src/trusted/service_runtime/nacl_copy.h"
+#include "native_client/src/trusted/service_runtime/sel_ldr.h"
+
+namespace {
+
+class ScopedCopyLock {
+ public:
+  explicit ScopedCopyLock(struct NaClApp* nap) : nap_(nap) {
+    NaClCopyTakeLock(nap_);
+  }
+  ~ScopedCopyLock() {
+    NaClCopyDropLock(nap_);
+  }
+ private:
+  struct NaClApp* nap_;
+};
+
+static inline uintptr_t NaClUserToSysAddrArray(
+    struct NaClApp* nap,
+    uint32_t uaddr,
+    size_t count,
+    size_t size) {
+  // TODO(ncbray): overflow checking
+  size_t range = count * size;
+  return NaClUserToSysAddrRange(nap, uaddr, range);
+}
+
+template <typename T> bool ConvertScalarInput(
+    struct NaClApp* nap,
+    uint32_t user_ptr,
+    T* value) {
+  if (user_ptr) {
+    uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+    if (temp != kNaClBadAddress) {
+      *value = *reinterpret_cast<T volatile*>(temp);
+      return true;
+    }
+  }
+  return false;
+}
+
+template <typename T> bool ConvertScalarOutput(
+    struct NaClApp* nap,
+    uint32_t user_ptr,
+    T volatile** sys_ptr) {
+  if (user_ptr) {
+    uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+    if (temp != kNaClBadAddress) {
+      *sys_ptr = reinterpret_cast<T volatile*>(temp);
+      return true;
+    }
+  }
+  *sys_ptr = 0; // Paranoia.
+  return false;
+}
+
+template <typename T> bool ConvertScalarInOut(
+    struct NaClApp* nap,
+    uint32_t user_ptr,
+    bool optional,
+    T* value,
+    T volatile** sys_ptr) {
+  if (user_ptr) {
+    uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+    if (temp != kNaClBadAddress) {
+      T volatile* converted = reinterpret_cast<T volatile*>(temp);
+      *sys_ptr = converted;
+      *value = *converted;
+      return true;
+    }
+  } else if (optional) {
+    *sys_ptr = 0;
+    *value = static_cast<T>(0); // Paranoia.
+    return true;
+  }
+  *sys_ptr = 0; // Paranoia.
+  *value = static_cast<T>(0); // Paranoia.
+  return false;
+}
+
+template <typename T> bool ConvertArray(
+    struct NaClApp* nap,
+    uint32_t user_ptr,
+    uint32_t length,
+    size_t element_size,
+    bool optional,
+    T** sys_ptr) {
+  if (user_ptr) {
+    uintptr_t temp = NaClUserToSysAddrArray(nap, user_ptr, length,
+                                            element_size);
+    if (temp != kNaClBadAddress) {
+      *sys_ptr = reinterpret_cast<T*>(temp);
+      return true;
+    }
+  } else if (optional) {
+    *sys_ptr = 0;
+    return true;
+  }
+  return false;
+}
+
+template <typename T> bool ConvertBytes(
+    struct NaClApp* nap,
+    uint32_t user_ptr,
+    uint32_t length,
+    bool optional,
+    T** sys_ptr) {
+  if (user_ptr) {
+    uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, length);
+    if (temp != kNaClBadAddress) {
+      *sys_ptr = reinterpret_cast<T*>(temp);
+      return true;
+    }
+  } else if (optional) {
+    *sys_ptr = 0;
+    return true;
+  }
+  return false;
+}
+
+// TODO(ncbray): size validation and complete copy.
+// TODO(ncbray): ensure non-null / missized structs are covered by a test case.
+template <typename T> bool ConvertStruct(
+    struct NaClApp* nap,
+    uint32_t user_ptr,
+    bool optional,
+    T** sys_ptr) {
+  if (user_ptr) {
+    uintptr_t temp = NaClUserToSysAddrRange(nap, user_ptr, sizeof(T));
+    if (temp != kNaClBadAddress) {
+      *sys_ptr = reinterpret_cast<T*>(temp);
+      return true;
+    }
+  } else if (optional) {
+    *sys_ptr = 0;
+    return true;
+  }
+  return false;
+}
+
+} // namespace
+
+#endif // MOJO_NACL_MOJO_SYSCALL_INTERNAL_H_
diff --git a/mojo/nacl/monacl_sel_main.cc b/mojo/nacl/monacl_sel_main.cc
new file mode 100644
index 0000000..4fbc575
--- /dev/null
+++ b/mojo/nacl/monacl_sel_main.cc
@@ -0,0 +1,52 @@
+// 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.
+
+#include "mojo/nacl/monacl_sel_main.h"
+
+#include <stdio.h>
+
+#include "mojo/nacl/mojo_syscall.h"
+#include "native_client/src/public/chrome_main.h"
+#include "native_client/src/public/nacl_app.h"
+#include "native_client/src/trusted/desc/nacl_desc_io.h"
+#include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
+
+namespace mojo {
+
+void LaunchNaCl(const char* nexe_file, const char* irt_file,
+                int app_argc, char* app_argv[]) {
+  NaClChromeMainInit();
+
+  // Open the IRT.
+  struct NaClDesc* irt_desc = (struct NaClDesc*) NaClDescIoDescOpen(
+      irt_file, NACL_ABI_O_RDONLY, 0);
+  if (NULL == irt_desc) {
+    perror(irt_file);
+    exit(1);
+  }
+
+  // Open the main executable.
+  struct NaClDesc* nexe_desc = (struct NaClDesc*) NaClDescIoDescOpen(
+      nexe_file, NACL_ABI_O_RDONLY, 0);
+  if (NULL == nexe_desc) {
+    perror(nexe_file);
+    exit(1);
+  }
+
+  struct NaClChromeMainArgs* args = NaClChromeMainArgsCreate();
+  args->nexe_desc = nexe_desc;
+  args->irt_desc = irt_desc;
+
+  args->argc = app_argc;
+  args->argv = app_argv;
+
+  struct NaClApp* nap = NaClAppCreate();
+  InjectMojo(nap);
+
+  int exit_status = 1;
+  NaClChromeMainStart(nap, args, &exit_status);
+  NaClExit(exit_status);
+}
+
+} // namespace mojo
diff --git a/mojo/nacl/monacl_sel_main.h b/mojo/nacl/monacl_sel_main.h
new file mode 100644
index 0000000..f543d16
--- /dev/null
+++ b/mojo/nacl/monacl_sel_main.h
@@ -0,0 +1,15 @@
+// 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 MOJO_NACL_MONACL_SEL_MAIN_H_
+#define MOJO_NACL_MONACL_SEL_MAIN_H_
+
+namespace mojo {
+
+void LaunchNaCl(const char* nexe_file, const char* irt_file,
+                int app_argc, char* app_argv[]);
+
+} // namespace mojo
+
+#endif // MOJO_NACL_MONACL_SEL_MAIN_H_
diff --git a/mojo/nacl/monacl_shell.cc b/mojo/nacl/monacl_shell.cc
new file mode 100644
index 0000000..7922d9a
--- /dev/null
+++ b/mojo/nacl/monacl_shell.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include <iostream>
+
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/edk/embedder/simple_platform_support.h"
+#include "mojo/nacl/monacl_sel_main.h"
+
+
+int main(int argc, char* argv[]) {
+  if (argc < 3) {
+    std::cout << "Usage: " << argv[0] << " irt.nexe app.nexe [args for app]" <<
+        std::endl;
+    return 1;
+  }
+
+  const char* irt_file = argv[1];
+  const char* nexe_file = argv[2];
+
+  mojo::embedder::Init(scoped_ptr<mojo::embedder::PlatformSupport>(
+      new mojo::embedder::SimplePlatformSupport()));
+
+  // Does not return.
+  mojo::LaunchNaCl(nexe_file, irt_file, argc - 2, argv + 2);
+  return 1;
+}