Initial checkin of COMROGUE source after having gotten initial memory map right

This commit is contained in:
Eric J. Bowersox 2013-04-11 02:10:10 -06:00
commit 5b93e58fb3
110 changed files with 29045 additions and 0 deletions

32
COPYRIGHT Normal file
View File

@ -0,0 +1,32 @@
The COMROGUE Operating System for Raspberry Pi
Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
All rights reserved.
This program is free for commercial and non-commercial use as long as the following conditions are
adhered to.
Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
in the code are not to be removed.
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.
THIS SOFTWARE IS 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 HOLDER 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.
Some files in the source have been obtained primarily from other sources, modified or not. Where applicable,
the original copyright headers remain in those source files.
"Raspberry Pi" is a trademark of the Raspberry Pi Foundation.

53
Makefile Normal file
View File

@ -0,0 +1,53 @@
#
# This file is part of the COMROGUE Operating System for Raspberry Pi
#
# Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
# All rights reserved.
#
# This program is free for commercial and non-commercial use as long as the following conditions are
# adhered to.
#
# Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
# in the code are not to be removed.
#
# 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.
#
# THIS SOFTWARE IS 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 HOLDER 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.
#
# "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
MAKEFLAGS += -rR
all: tools idl kernel
tools:
make -C tools
idl:
make -C idl
kernel:
make -C kernel
clean:
make -C tools clean
make -C idl clean
make -C kernel clean
cleanbackup:
find . -name '*~' -delete
.PHONY: tools idl kernel

View File

@ -0,0 +1,31 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/

View File

@ -0,0 +1,31 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/

View File

@ -0,0 +1,31 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/

View File

@ -0,0 +1,31 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/

View File

@ -0,0 +1,30 @@
#
# This file is part of the COMROGUE Operating System for Raspberry Pi
#
# Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
# All rights reserved.
#
# This program is free for commercial and non-commercial use as long as the following conditions are
# adhered to.
#
# Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
# in the code are not to be removed.
#
# 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.
#
# THIS SOFTWARE IS 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 HOLDER 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.
#
# "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.

View File

@ -0,0 +1,9 @@
--- COMROGUE 0.00
- KiSystemStartup
ATAG @ c0000100: 54410001[5]
- flags = 00000000, pgsiz = 0, root = 0
ATAG @ c0000114: 54410002[4]
- memory: 469762048 bytes at physaddr 00000000
ATAG @ c0000124: 54410009[95]
- cmdline: "dma.dmachans=0x7f35 bcm2708_fb.fbwidth=1360 bcm2708_fb.fbheight=768 bcm2708.boardrev=0xf bcm2708.serial=0x3368e8ee smsc95xx.macaddr=B8:27:EB:68:E8:EE sdhci-bcm2708.emmc_clock_freq=100000000 vc_mem.mem_base=0x1ec00000 vc_mem.mem_size=0x20000000 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
ATAG @ c00002a0: 00000000[0]

View File

@ -0,0 +1,23 @@
COMROGUEPrestart
EMmInit: TTB1@00010000
Map 00000000->00000000,cpg=0000000A,tf=00000001,pf=00000012
Map 20000000->20000000,cpg=00000400,tf=00000001,pf=00000012
Map 0000A000->B0000000,cpg=00000002,tf=00000001,pf=0000002E
Map 0000C000->C0000000,cpg=00000001,tf=00000001,pf=0000001E
Map 0000D000->C0001000,cpg=00000000,tf=00000001,pf=0000001F
Map 0000D000->C0001000,cpg=00000001,tf=00000001,pf=0000001E
Map 0000E000->C0002000,cpg=00000002,tf=00000001,pf=0000001F
Map 00010000->C0004000,cpg=00000004,tf=00000001,pf=0000001F
Map 00014000->C0008000,cpg=00000080,tf=00000001,pf=0000001F
Map 20000000->E0000000,cpg=00000400,tf=00000001,pf=00000012
--- COMROGUE 0.00
- KiSystemStartup
Mach type c42, revision f, serial 3368e8ee
Memory: 131072 total pages (114688 available), 0 TTB gap
TTB1 @ PA 00010000, VMA C0004000
MPDB @ PA 00014000, VMA C0008000, 128 pages
Page tables @ PA 00094000, 2 pages, 1 free on last one
First free PA = 00096000, first free VMA = C0088000
EMMC clock freq = 100000000
VC memory is at PHYS:1EC00000, 536870912 bytes, framebuffer 1360x768
MAC address B8:27:EB:68:E8:EE

45
idl/Makefile Normal file
View File

@ -0,0 +1,45 @@
#
# This file is part of the COMROGUE Operating System for Raspberry Pi
#
# Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
# All rights reserved.
#
# This program is free for commercial and non-commercial use as long as the following conditions are
# adhered to.
#
# Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
# in the code are not to be removed.
#
# 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.
#
# THIS SOFTWARE IS 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 HOLDER 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.
#
# "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
MAKEFLAGS += -rR
PIDL = ../tools/pidl/pidl
IDL_FILES := $(wildcard comrogue/*.idl)
H_FILES := $(subst .idl,.h,${IDL_FILES})
all: ${H_FILES}
%.h: %.idl
${PIDL} --includedir . --comrogue-header=$@ -- $<
clean:
-rm comrogue/*.h

View File

@ -0,0 +1,106 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
/*---------------------------------------------------------
* Standard data type declarations for COMROGUE interfaces
*---------------------------------------------------------
*/
[uuid(b381db2c-471e-4288-ba62-878be5ceb393), version(0.1), pointer_default(unique)]
interface ICOMROGUETypes
{
/* Integral type definitions */
typedef int16 INT16;
typedef uint16 UINT16;
typedef int32 INT32;
typedef uint32 UINT32;
typedef dlong INT64;
typedef udlong UINT64;
typedef INT32 INT_PTR;
typedef UINT32 UINT_PTR;
/* Base pointer type definitions */
typedef INT16 *PINT16;
typedef UINT16 *PUINT16;
typedef INT32 *PINT32;
typedef UINT32 *PUINT32;
typedef INT64 *PINT64;
typedef UINT64 *PUINT64;
typedef void *PVOID;
typedef const void *PCVOID;
/* Pointer-to-pointer definitions */
typedef PVOID *PPVOID;
/* Character types */
typedef char CHAR;
typedef uint8 UCHAR;
typedef uint8 BYTE;
typedef CHAR *PCHAR;
typedef const CHAR *PCCHAR;
typedef UCHAR *PUCHAR;
[string] typedef CHAR *PSTR;
[string] typedef const CHAR *PCSTR;
/* Boolean type */
typedef int BOOL;
/* Status code/result types */
typedef UINT32 SCODE;
typedef SCODE HRESULT;
/* GUID typedefs */
typedef struct tagGUID {
UINT32 Data1;
UINT16 Data2;
UINT16 Data3;
BYTE Data4[8];
} GUID;
typedef GUID IID;
typedef GUID CLSID;
/* The reference types are defined specially so we can use C++ references where necessary */
cpp_quote("#if !defined(__cplusplus) || defined(CINTERFACE)")
typedef const GUID *REFGUID;
typedef const IID *REFIID;
typedef const CLSID *REFCLSID;
cpp_quote("#endif")
}
cpp_quote("#if defined(__cplusplus) && !defined(CINTERFACE)")
cpp_quote("typedef const GUID& REFGUID;")
cpp_quote("typedef const IID& REFIID;")
cpp_quote("typedef const CLSID& REFCLSID;")
cpp_quote("#endif")

View File

@ -0,0 +1,58 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
import "comrogue/object_types.idl";
/*--------------------
* IUnknown interface
*--------------------
*/
[object, uuid(00000000-0000-0000-C000-000000000046), pointer_default(unique)]
interface IUnknown
{
[unique] typedef IUnknown *PUNKNOWN;
HRESULT QueryInterface([in] REFIID riid, [out, iid_is(riid)] PPVOID ppvObject);
UINT32 AddRef();
UINT32 Release();
}
/*----------------------------
* IServiceProvider interface
*----------------------------
*/
[object, uuid(6d5140c1-7436-11ce-8034-00aa006009fa), pointer_default(unique)]
interface IServiceProvider : IUnknown
{
[unique] typedef IServiceProvider *PSERVICEPROVIDER;
HRESULT QueryService([in] REFGUID guidService, [in] REFIID riid, [out, iid_is(riid)] PPVOID ppvObject);
}

View File

@ -0,0 +1,58 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __COMPILER_MACROS_H_INCLUDED
#define __COMPILER_MACROS_H_INCLUDED
#ifndef __ASM__
/*--------------------------------------------------------------------------
* Compiler macros for differentiationg between C++ and C compilation, etc.
*--------------------------------------------------------------------------
*/
#ifdef __cplusplus
#define EXTERN_C extern "C"
#define CDECL_BEGIN extern "C" {
#define CDECL_END }
#else
#define EXTERN_C
#define CDECL_BEGIN
#define CDECL_END
#endif /* __cplusplus */
#endif /* __ASM__ */
#endif /* __COMPILER_MACROS_H_INCLUDED */

View File

@ -0,0 +1,141 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __X__16550_H_INCLUDED
#define __X__16550_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
/*------------------------------------------------------------------------------------------------------------
* Standard bits used in the registers of a 16550 UART. Note that not all of these bits are supported by the
* BCM2835 mini-UART; they are included here for completeness.
*------------------------------------------------------------------------------------------------------------
*/
/* Interrupt Enable Register (read/write) */
#define U16550_IER_RXREADY 0x01 /* Receive Ready interrupt */
#define U16550_IER_TXEMPTY 0x02 /* Transmit Empty interrupt */
#define U16550_IER_ERRBRK 0x04 /* Error/Break iterrupt */
#define U16550_IER_SINPUT 0x08 /* Status change interrupt */
/* Interrupt Identification Register (read-only) */
#define U16550_IIR_NOPENDING 0x01 /* Set if no interrupt is pending */
#define U16550_IIR_ID_MASK 0x0E /* Pending interrupt mask */
#define U16550_IIR_ID_ERRBRK 0x06 /* Error/Break interrupt */
#define U16550_IIR_ID_RXREADY 0x04 /* Receive Ready interrupt */
#define U16550_IIR_ID_RXTIMEOUT 0x0C /* Receive Timeout interrupt */
#define U16550_IIR_ID_TXEMPTY 0x02 /* Transmit Empty interrupt */
#define U16550_IIR_ID_SINPUT 0x00 /* Status change interrupt */
#define U16550_IIR_RXFIFO 0x40 /* Receive FIFO enabled */
#define U16550_IIR_TXFIFO 0x80 /* Transmit FIFO enabled */
/* FIFO Control Register (write-only) */
#define U16550_FCR_ENABLE 0x01 /* Enable FIFOs */
#define U16550_FCR_RXCLEAR 0x02 /* Clear receive FIFO */
#define U16550_FCR_TXCLEAR 0x04 /* Clear transmit FIFO */
#define U16550_FCR_MODE 0x08 /* FIFO mode select */
#define U16550_FCR_LEVEL_MASK 0xC0 /* FIFO level mask */
#define U16550_FCR_LEVEL_1 0x00 /* FIFO level: 1 character */
#define U16550_FCR_LEVEL_4 0x40 /* FIFO level: 4 characters */
#define U16550_FCR_LEVEL_8 0x80 /* FIFO level: 8 characters */
#define U16550_FCR_LEVEL_14 0xC0 /* FIFO level: 14 characters */
/* Line Control Register (read/write) */
#define U16550_LCR_LENGTH_MASK 0x03 /* Data length control mask */
#define U16550_LCR_LENGTH_5 0x00 /* Data length: 5 bits */
#define U16550_LCR_LENGTH_6 0x01 /* Data length: 6 bits */
#define U16550_LCR_LENGTH_7 0x02 /* Data length: 7 bits */
#define U16550_LCR_LENGTH_8 0x03 /* Data length: 8 bits */
#define U16550_LCR_STOP 0x04 /* Set = 2 stop bits, Clear = 1 stop bit */
#define U16550_LCR_PARITY_MASK 0x38 /* Parity control mask */
#define U16550_LCR_PARITY_NONE 0x00 /* Parity: NONE */
#define U16550_LCR_PARITY_ODD 0x08 /* Parity: ODD */
#define U16550_LCR_PARITY_EVEN 0x18 /* Parity: EVEN */
#define U16550_LCR_PARITY_MARK 0x28 /* Parity: MARK */
#define U16550_LCR_PARITY_SPACE 0x38 /* Parity: SPACE */
#define U16550_LCR_BREAK 0x40 /* Send BREAK when set */
#define U16550_LCR_DLAB 0x80 /* Divisor Latch Access Bit */
/* Modem Control Register (read/write) */
#define U16550_MCR_DTR 0x01 /* Set Data Terminal Ready */
#define U16550_MCR_RTS 0x02 /* Set Request To Send */
#define U16550_MCR_OP1 0x04 /* Set General-Purpose Output 1 */
#define U16550_MCR_OP2 0x08 /* Set General-Purpose Output 2 */
#define U16550_MCR_LOOPBACK 0x10 /* Loopback test mode */
/* Line Status Register (read-only) */
#define U16550_LSR_RXDATA 0x01 /* Received data ready */
#define U16550_LSR_OVERRUNERR 0x02 /* Receiver overrun error */
#define U16550_LSR_PARITYERR 0x04 /* Parity error */
#define U16550_LSR_FRAMEERR 0x08 /* Framing error */
#define U16550_LSR_BREAK 0x10 /* BREAK detected */
#define U16550_LSR_TXBUFEMPTY 0x20 /* Transmitter buffer empty */
#define U16550_LSR_TXEMPTY 0x40 /* Transmitter empty */
/* Modem Status Register (read-only) */
#define U16550_MSR_DELTA_CTS 0x01 /* change in Clear To Send line */
#define U16550_MSR_DELTA_DSR 0x02 /* change in Data Set Ready line */
#define U16550_MSR_DELTA_RI 0x04 /* change in Ring Indicator line */
#define U16550_MSR_DELTA_CD 0x08 /* change in Carrier Detect line */
#define U16550_MSR_CTS 0x10 /* Clear To Send */
#define U16550_MSR_DSR 0x20 /* Data Set Ready */
#define U16550_MSR_RI 0x40 /* Ring Indicator */
#define U16550_MSR_CD 0x80 /* Carrier Detect */
/* BCM2835-specific: Auxiliary control register (read/write) */
#define AUXMU_CNTL_RXENABLE 0x00000001 /* Receiver enable */
#define AUXMU_CNTL_TXENABLE 0x00000002 /* Transmitter enable */
#define AUXMU_CNTL_RXAUTOFLOW 0x00000004 /* Reciever auto-flow-control enabled */
#define AUXMU_CNTL_TXAUTOFLOW 0x00000008 /* Transmitter auto-flow-control enabled */
#define AUXMU_CNTL_RXAUTO_MASK 0x00000030 /* Receiver auto-flow-control level */
#define AUXMU_CNTL_RXAUTO_3 0x00000000 /* Receiver auto-flow-control: 3 spaces remaining */
#define AUXMU_CNTL_RXAUTO_2 0x00000010 /* Receiver auto-flow-control: 2 spaces remaining */
#define AUXMU_CNTL_RXAUTO_1 0x00000020 /* Receiver auto-flow-control: 1 space remaining */
#define AUXMU_CNTL_RXAUTO_4 0x00000030 /* Receiver auto-flow-control: 4 spaces remaining */
#define AUXMU_CNTL_RTSASSERT 0x00000040 /* RTS assert level invert */
#define AUXMU_CNTL_CTSASSERT 0x00000080 /* CTS assert level invert */
/* BCM2835-specific: Auxiliary status register (read-only) */
#define AUXMU_STAT_RXREADY 0x00000001 /* Receive ready */
#define AUXMU_STAT_TXREADY 0x00000002 /* Transmit ready */
#define AUXMU_STAT_RXIDLE 0x00000004 /* Receiver idle */
#define AUXMU_STAT_TXIDLE 0x00000008 /* Transmitter idle */
#define AUXMU_STAT_RXOVERRUN 0x00000010 /* Receiver overrun */
#define AUXMU_STAT_TXFULL 0x00000020 /* Transmit FIFO is full */
#define AUXMU_STAT_RTS 0x00000040 /* Request To Send line */
#define AUXMU_STAT_CTS 0x00000080 /* Clear To Send line */
#define AUXMU_STAT_TXDONE 0x00000100 /* Transmitter done (Tx idle, FIFO empty) */
#define AUXMU_STAT_RXLEVEL_MASK 0x000F0000 /* Receive FIFO fill level mask */
#define AUXMU_STAT_TXLEVEL_MASK 0x0F000000 /* Transmit FIFO fill level mask */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __X__16550_H_INCLUDED */

View File

@ -0,0 +1,58 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __ASM_MACROS_H_INCLUDED
#define __ASM_MACROS_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
#ifndef __ASM__
#error "This file should be included in assembly language code only"
#endif
/* Instruction barrier macro */
.macro instr_barrier
mcr p15, 0, r0, c7, c5, 4
.endm
/* Data synchronization barrier macro */
.macro data_sync_barrier
mcr p15, 0, r0, c7, c10, 4
.endm
/* Data memory barrier macro */
.macro data_memory_barrier
mcr p15, 0, r0, c7, c10, 5
.endm
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __ASM_MACROS_H_INCLUDED */

View File

@ -0,0 +1,81 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __AUXDEV_H_INCLUDED
#define __AUXDEV_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
/*-------------------------------
* BCM2835 auxiliary peripherals
*-------------------------------
*/
/* Register physical addresses */
#define AUX_REG_IRQ 0x20215000 /* AUX interrupt status */
#define AUX_REG_ENABLE 0x20215004 /* AUX enable */
#define AUX_MU_REG_THR 0x20215040 /* Mini-UART Transmitter Holding Register */
#define AUX_MU_REG_RHR 0x20215040 /* Mini-UART Receiver Holding Register */
#define AUX_MU_REG_IER 0x20215044 /* Mini-UART Interrupt Enable Register */
#define AUX_MU_REG_IIR 0x20215048 /* Mini-UART Interrupt Identification Register */
#define AUX_MU_REG_FCR 0x20215048 /* Mini-UART FIFO Control Register */
#define AUX_MU_REG_LCR 0x2021504C /* Mini-UART Line Control Register */
#define AUX_MU_REG_MCR 0x20215050 /* Mini-UART Modem Control Register */
#define AUX_MU_REG_LSR 0x20215054 /* Mini-UART Line Status Register */
#define AUX_MU_REG_MSR 0x20215058 /* Mini-UART Modem Status Register */
#define AUX_MU_REG_SCR 0x2021505C /* Mini-UART Scratch Register */
#define AUX_MU_REG_CNTL 0x20215060 /* Mini-UART Auxiliary Control Register */
#define AUX_MU_REG_STAT 0x20215064 /* Mini-UART Auxiliary Status Register */
#define AUX_MU_REG_BAUD 0x20215068 /* Mini-UART Baud Rate Register */
#define AUX_SPI0_REG_CTL0 0x20215080 /* SPI 0 Control Register 0 */
#define AUX_SPI0_REG_CTL1 0x20215084 /* SPI 0 Control Register 1 */
#define AUX_SPI0_REG_STAT 0x20215088 /* SPI 0 Status Register */
#define AUX_SPI0_REG_IO 0x20215090 /* SPI 0 Data Register */
#define AUX_SPI0_REG_PEEK 0x20215094 /* SPI 0 Peek Register */
#define AUX_SPI1_REG_CTL0 0x202150C0 /* SPI 1 Control Register 0 */
#define AUX_SPI1_REG_CTL1 0x202150C4 /* SPI 1 Control Register 1 */
#define AUX_SPI1_REG_STAT 0x202150C8 /* SPI 1 Status Register */
#define AUX_SPI1_REG_IO 0x202150D0 /* SPI 1 Data Register */
#define AUX_SPI1_REG_PEEK 0x202150D4 /* SPI 1 Peek Register */
/* AUX IRQ register bits */
#define AUX_IRQ_MU 0x00000001 /* Mini-UART has interrupt pending */
#define AUX_IRQ_SPI0 0x00000002 /* SPI 0 has interrupt pending */
#define AUX_IRQ_SPI1 0x00000004 /* SPI 1 has interrupt pending */
/* AUX Enable register bits */
#define AUX_ENABLE_MU 0x00000001 /* Mini-UART enable */
#define AUX_ENABLE_SPI0 0x00000002 /* SPI 0 enable */
#define AUX_ENABLE_SPI1 0x00000004 /* SPI 1 enable */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __AUXDEV_H_INCLUDED__ */

View File

@ -0,0 +1,93 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __GPIO_H_INCLUDED
#define __GPIO_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
/*--------------------
* BCM2835 GPIO lines
*--------------------
*/
/* GPIO register physical addresses */
#define GPFSEL0_REG 0x20200000 /* GPIO Function Select 0 (lines 0-9) */
#define GPFSEL1_REG 0x20200004 /* GPIO Function Select 1 (lines 10-19) */
#define GPFSEL2_REG 0x20200008 /* GPIO Function Select 2 (lines 20-29) */
#define GPFSEL3_REG 0x2020000C /* GPIO Function Select 3 (lines 30-39) */
#define GPFSEL4_REG 0x20200010 /* GPIO Function Select 4 (lines 40-49) */
#define GPFSEL5_REG 0x20200014 /* GPIO Function Select 5 (lines 50-53) */
#define GPSET0_REG 0x2020001C /* GPIO Output Set 0 (lines 0-31) */
#define GPSET1_REG 0x20200020 /* GPIO Output Set 1 (lines 32-53) */
#define GPCLR0_REG 0x20200028 /* GPIO Output Clear 0 (lines 0-31) */
#define GPCLR1_REG 0x2020002C /* GPIO Output Clear 1 (lines 32-53) */
#define GPLEV0_REG 0x20200034 /* GPIO Pin Level Detect 0 (lines 0-31) */
#define GPLEV1_REG 0x20200038 /* GPIO Pin Level Detect 1 (lines 32-53) */
#define GPEDS0_REG 0x20200040 /* GPIO Pin Event Detect Status 0 (lines 0-31) */
#define GPEDS1_REG 0x20200044 /* GPIO Pin Event Detect Status 1 (lines 32-53) */
#define GPREN0_REG 0x2020004C /* GPIO Pin Rising Edge Detect Enable 0 (lines 0-31) */
#define GPREN1_REG 0x20200050 /* GPIO Pin Rising Edge Detect Enable 1 (lines 32-53) */
#define GPFEN0_REG 0x20200085 /* GPIO Pin Falling Edge Detect Enable 0 (lines 0-31) */
#define GPFEN1_REG 0x2020005C /* GPIO Pin Falling Edge Detect Enable 1 (lines 32-53) */
#define GPHEN0_REG 0x20200064 /* GPIO Pin High Level Detect Enable 0 (lines 0-31) */
#define GPHEN1_REG 0x20200068 /* GPIO Pin High Level Detect Enable 1 (lines 32-53) */
#define GPLEN0_REG 0x20200070 /* GPIO Pin Low Level Detect Enable 0 (lines 0-31) */
#define GPLEN1_REG 0x20200074 /* GPIO Pin Low Level Detect Enable 1 (lines 32-53) */
#define GPAREN0_REG 0x2020007C /* GPIO Pin Async Rising Edge Detect Enable 0 (lines 0-31) */
#define GPAREN1_REG 0x20200080 /* GPIO Pin Async Rising Edge Detect Enable 1 (lines 32-53) */
#define GPAFEN0_REG 0x20200088 /* GPIO Pin Async Falling Edge Detect Enable 0 (lines 0-31) */
#define GPAFEN1_REG 0x2020008C /* GPIO Pin Async Falling Edge Detect Enable 1 (lines 32-53) */
#define GPPUD_REG 0x20200094 /* GPIO Pin Pull-up/down Enable */
#define GPPUDCLK0_REG 0x20200098 /* GPIO Pin Pull-up/down Enable Clock 0 (lines 0-31) */
#define GPPUDCLK1_REG 0x2020009C /* GPIO Pin Pull-up/down Enable Clock 1 (lines 32-53) */
#define GP_PIN_MASK 0x0007 /* GPIO pin function select mask */
#define GP_PIN_INPUT 0x0000 /* GPIO pin function is input */
#define GP_PIN_OUTPUT 0x0001 /* GPIO pin function is output */
#define GP_PIN_ALT0 0x0004 /* GPIO pin alternate function 0 */
#define GP_PIN_ALT1 0x0005 /* GPIO pin alternate function 1 */
#define GP_PIN_ALT2 0x0006 /* GPIO pin alternate function 2 */
#define GP_PIN_ALT3 0x0007 /* GPIO pin alternate function 3 */
#define GP_PIN_ALT4 0x0003 /* GPIO pin alternate function 4 */
#define GP_PIN_ALT5 0x0002 /* GPIO pin alternate function 5 */
#define GP_FUNC_MASK(n) (GP_PIN_MASK << ((n) * 3))
#define GP_FUNC_BITS(n, bits) (((bits) & GP_PIN_MASK) << ((n) * 3))
#define GP_BIT(n) (1 << (n))
#define GPPUD_DISABLE 0x0000 /* Disable pull-up/pull-down */
#define GPPUD_PULLDOWN 0x0001 /* Enable pull-down */
#define GPPUD_PULLUP 0x0002 /* Enable pull-up */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __GPIO_H_INCLUDED */

View File

@ -0,0 +1,52 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __LAYOUT_H_INCLUDED
#define __LAYOUT_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
/*-----------------------------------------------------------
* Constants defining the layout of the COMROGUE memory map.
*-----------------------------------------------------------
*/
#define PHYSADDR_LOAD 0x8000 /* physical address at which the loader loads the kernel */
#define PHYSADDR_IO_BASE 0x20000000 /* physical address that's the base for memory-mapped IO */
#define VMADDR_TTB_FENCE 0x80000000 /* address that's the dividing point between TTBs */
#define VMADDR_LIBRARY_FENCE 0xB0000000 /* base address for kernel "shared library" code */
#define VMADDR_KERNEL_FENCE 0xC0000000 /* base address for the internal kernel code */
#define VMADDR_IO_BASE 0xE0000000 /* base address for memory-mapped IO */
#define PAGE_COUNT_IO 1024 /* 4 megabytes mapped for IO */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __LAYOUT_H_INCLUDED */

View File

@ -0,0 +1,51 @@
#ifndef __LLIO_H_INCLUDED
#define __LLIO_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
#ifndef __ASM__
#include <comrogue/types.h>
#include <comrogue/compiler_macros.h>
/*--------------------------------------------------------------------------------------
* Functions for performing low-level IO (direct read and write of memory-mapped ports)
*--------------------------------------------------------------------------------------
*/
#ifdef __COMROGUE_PRESTART__
CDECL_BEGIN
extern void llIOWritePA(PHYSADDR paPort, UINT32 uiData);
extern UINT32 llIOReadPA(PHYSADDR paPort);
extern void llIODelayPA(UINT32 uiTicks);
#define llIOWrite(addr, data) llIOWritePA(addr, data)
#define llIORead(addr) llIOReadPA(addr)
#define llIODelay(ticks) llIODelayPA(ticks)
CDECL_END
#else
CDECL_BEGIN
extern void llIOWriteK(KERNADDR kaPort, UINT32 uiData);
extern UINT32 llIOReadK(KERNADDR kaPort);
extern void llIODelay(UINT32 uiTicks);
CDECL_END
#define _LLIOMAP(addr) ((addr) + 0xC0000000)
#define llIOWrite(addr, data) llIOWriteK(_LLIOMAP(addr), data)
#define llIORead(addr) llIOReadK(_LLIOMAP(addr))
#endif /* __COMROGUE_PRESTART__ */
#endif /* __ASM__ */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __LLIO_H_INCLUDED */

View File

@ -0,0 +1,241 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __MMU_H_INCLUDED
#define __MMU_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
/*----------------------------------------------
* BCM2835 ARM Memory Management Unit constants
*----------------------------------------------
*/
/* Memory system constants */
#define SYS_PAGE_SIZE 4096 /* standard page size for normal page */
#define SYS_PAGE_BITS 12 /* log2(SYS_PAGE_SIZE), number of bits in a page address */
#define SYS_TTB0_SIZE 8192 /* TTB0 must be located on this boundary and is this size */
#define SYS_TTB1_SIZE 16384 /* TTB1 must be located on this boundary and is this size */
#define SYS_TTB1_ENTRIES 4096 /* SYS_TTB1_SIZE/4, number of entries in TTB1 */
#define SYS_TTB_BITS 12 /* log2(SYS_TTB1_SIZE/4), number of bits in a TTB address */
#define SYS_SEC_SIZE 1048576 /* standard section size */
#define SYS_SEC_PAGES 256 /* SYS_SEC_SIZE/SYS_PAGE_SIZE, number of pages equivalent to a section */
#define SYS_PGTBL_SIZE 1024 /* page tables must be located on this boundary and are this size */
#define SYS_PGTBL_BITS 8 /* log2(SYS_PGTBL_SIZE/4), number of bits in a page table address */
#define SYS_PGTBL_ENTRIES 256 /* SYS_PGTBL_SIZE/4, number of entries in a page table */
/* Section descriptor bits */
#define TTBSEC_PXN 0x00000001 /* Privileged Execute-Never */
#define TTBSEC_ALWAYS 0x00000002 /* this bit must always be set for a section */
#define TTBSEC_B 0x00000004 /* memory region attribute bit */
#define TTBSEC_C 0x00000008 /* memory region attribute bit */
#define TTBSEC_XN 0x00000010 /* Execute-Never */
#define TTBSEC_DOM_MASK 0x000001E0 /* domain indicator */
#define TTBSEC_P 0x00000200 /* ECC enabled (not supported) */
#define TTBSEC_AP 0x00000C00 /* access permission bits */
#define TTBSEC_TEX 0x00007000 /* memory type flags */
#define TTBSEC_APX 0x00008000 /* access permission extended */
#define TTBSEC_S 0x00010000 /* Shared */
#define TTBSEC_NG 0x00020000 /* Not Global */
#define TTBSEC_SUPER 0x00040000 /* Set for supersections */
#define TTBSEC_NS 0x00080000 /* Not Secure */
#define TTBSEC_ALLFLAGS 0x000FFFFF /* "all flags" mask */
#define TTBSEC_BASE 0xFFF00000 /* section base address mask */
#define TTBSEC_SBASE 0xFF000000 /* supersection base address mask */
#define TTBSEC_SBASEHI 0x00F00000 /* supersection high base address mask */
/* AP bits for the standard access control model */
#define TTBSEC_AP00 0x00000000 /* no access */
#define TTBSEC_AP01 0x00000400 /* supervisor only access */
#define TTBSEC_AP10 0x00000800 /* user read-only access */
#define TTBSEC_AP11 0x00000C00 /* user read-write access */
/* AP bits for the simplified access control model */
#define TTBSEC_ACCESS 0x00000400 /* Accessed bit */
#define TTBSEC_AP_PL0 0x00000800 /* enable access at PL0 */
#define TTBSEC_AP_RO TTBSEC_APX /* read-only access */
/* Page table descriptor bits */
#define TTBPGTBL_ALWAYS 0x00000001 /* bottom-two bits are always this */
#define TTBPGTBL_PXN 0x00000004 /* Privileged Execute-Never */
#define TTBPGTBL_NS 0x00000008 /* Not Secure */
#define TTBPGTBL_DOM_MASK 0x000001E0 /* domain indicator */
#define TTBPGTBL_P 0x00000200 /* ECC enabled (not supported) */
#define TTBPGTBL_ALLFLAGS 0x000003FF /* "all flags" mask */
#define TTBPGTBL_BASE 0xFFFFFC00 /* page table base address mask */
/* Bits to query the type of TTB entry we're looking at */
#define TTBQUERY_MASK 0x00000003 /* bits we can query */
#define TTBQUERY_FAULT 0x00000000 /* indicates a fault */
#define TTBQUERY_PGTBL 0x00000001 /* indicates a page table */
#define TTBQUERY_SEC 0x00000002 /* indicates a section */
#define TTBQUERY_PXNSEC 0x00000003 /* indicates a section with PXN (or reserved) */
/* Small page table entry bits */
#define PGTBLSM_XN 0x00000001 /* Execute-Never */
#define PGTBLSM_ALWAYS 0x00000002 /* this bit must always be set for a page table entry */
#define PGTBLSM_B 0x00000004 /* memory region attribute bit */
#define PGTBLSM_C 0x00000008 /* memory region attribute bit */
#define PGTBLSM_AP 0x00000030 /* access permission bits */
#define PGTBLSM_TEX 0x000001C0 /* memory type flags */
#define PGTBLSM_APX 0x00000200 /* access permission extended */
#define PGTBLSM_S 0x00000400 /* Shared */
#define PGTBLSM_NG 0x00000800 /* Not Global */
#define PGTBLSM_PAGE 0xFFFFF000 /* page base address mask */
/* AP bits for the standard access control model */
#define PGTBLSM_AP00 0x00000000 /* no access */
#define PGTBLSM_AP01 0x00000010 /* supervisor only access */
#define PGTBLSM_AP10 0x00000020 /* user read-only access */
#define PGTBLSM_AP11 0x00000030 /* user read-write access */
/* Bits to query the type of page table entry we're looking at */
#define PGQUERY_MASK 0x00000003 /* bits we can query */
#define PGQUERY_FAULT 0x00000000 /* indicates a fault */
#define PGQUERY_LG 0x00000001 /* large page (64K) */
#define PGQUERY_SM 0x00000002 /* small page (4K) */
#define PGQUERY_SM_XN 0x00000003 /* small page with Execute-Never set */
#ifndef __ASM__
/*-------------------------------------------------------
* Data structures defining the TTB and page table data.
*-------------------------------------------------------
*/
/* TTB fault descriptor */
typedef struct tagTTBFAULT {
unsigned always0 : 2; /* bits are always 0 for a fault entry */
unsigned ignored : 30; /* ignored (COMROGUE may define these later) */
} TTBFAULT, *PTTBFAULT;
/* TTB page table descriptor */
typedef struct tagTTBPGTBL {
unsigned always01 : 2; /* bits are always 01 for a page table */
unsigned pxn : 1; /* Privileged Execute-Never bit */
unsigned ns : 1; /* Not Secure bit */
unsigned always0 : 1; /* bit is always 0 for a page table */
unsigned domain : 4; /* protection domain */
unsigned p : 1; /* not supported, should be 0 */
unsigned baseaddr : 22; /* upper 22 bits of base address of page table */
} TTBPGTBL, *PTTBPGTBL;
/* TTB section descriptor */
typedef struct tagTTBSEC {
unsigned pxn : 1; /* Privileged Execute-Never bit */
unsigned always1: 1; /* bit is always 1 for a section */
unsigned b : 1; /* attribute bit ("Buffered") */
unsigned c : 1; /* attribute bit ("Cached") */
unsigned xn : 1; /* Execute-Never bit */
unsigned domain : 4; /* protection domain */
unsigned p : 1; /* not supported, should be 0 */
unsigned ap : 2; /* access permissions */
unsigned tex : 3; /* memory type flags */
unsigned ap2 : 1; /* access permission extension */
unsigned s : 1; /* Shared bit */
unsigned ng : 1; /* Not Global bit */
unsigned always0 : 1; /* bit is always 0 for a section */
unsigned ns : 1; /* Not Secure bit */
unsigned baseaddr : 12; /* upper 12 bits of base address of section */
} TTBSEC, *PTTBSEC;
/* Single TTB entry descriptor */
typedef union tagTTB {
UINT32 data; /* raw data for entry */
TTBFAULT fault; /* "fault" data */
TTBPGTBL pgtbl; /* page table data */
TTBSEC sec; /* 1Mb section data */
} TTB, *PTTB;
/* page table descriptor for a fault entry */
typedef struct tagPGTBLFAULT {
unsigned always0 : 2; /* bits are always 0 for a fault entry */
unsigned ignored : 30; /* ignored (COMROGUE may define these later) */
} PGTBLFAULT, *PPGTBLFAULT;
/* page table descriptor for regular 4K pages */
typedef struct tagPGTBLSM {
unsigned xn : 1; /* Execute Never */
unsigned always1 : 1; /* always 1 for a 4k small page */
unsigned b : 1; /* attribute bit ("Buffered") */
unsigned c : 1; /* attribute bit ("Cached") */
unsigned ap : 2; /* access permissions */
unsigned tex : 3; /* memory type flags */
unsigned apx : 1; /* access permission extension */
unsigned s : 1; /* Shared bit */
unsigned ng : 1; /* Not Global bit */
unsigned pgaddr : 20; /* upper 20 bits of base address of page */
} PGTBLSM, *PPGTBLSM;
/* single page table entry */
typedef union tagPGTBL {
UINT32 data; /* raw data for entry */
PGTBLFAULT fault; /* "fault" data */
PGTBLSM pg; /* small page descriptor */
} PGTBL, *PPGTBL;
/* page table auxiliary entry */
typedef union tagPGAUX {
UINT32 data; /* raw data for entry */
/* TODO */
} PGAUX, *PPGAUX;
/* complete structure of a page table, hardware + auxiliary */
typedef struct tagPAGETAB {
PGTBL pgtbl[SYS_PGTBL_ENTRIES]; /* hardware page table entries */
PGAUX pgaux[SYS_PGTBL_ENTRIES]; /* auxiliary page table entries */
} PAGETAB, *PPAGETAB;
/* VMA index macros */
#define mmVMA2TTBIndex(vma) (((vma) >> (SYS_PAGE_BITS + SYS_PGTBL_BITS)) & ((1 << SYS_TTB_BITS) - 1))
#define mmVMA2PGTBLIndex(vma) (((vma) >> SYS_PAGE_BITS) & ((1 << SYS_PGTBL_BITS) - 1))
/*
* Data structures for the Master Page Database.
*/
/* internal structure of a MPDB entry */
typedef struct tagMPDB1 {
unsigned next : 20; /* index of "next" entry in list */
unsigned tag : 12; /* page tag */
} MPDB1;
/* The MPDB entry itself. */
typedef union tagMPDB {
UINT32 raw; /* raw data */
MPDB1 d; /* structured data */
} MPDB, *PMPDB;
#endif /* __ASM__ */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __MMU_H_INCLUDED */

View File

@ -0,0 +1,68 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __SCTLR_H_INCLUDED
#define __SCTLR_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
/*------------------------------------------------------
* Bits in the System Control Register (SCTLR), CP15 c1
*------------------------------------------------------
*/
#define SCTLR_M 0x00000001 /* MMU: 1 = enabled, 0 = disabled */
#define SCTLR_A 0x00000002 /* Alignment check: 1 = enabled, 0 = disabled */
#define SCTLR_C 0x00000004 /* Cache: 1 = enabled, 0 = disabled */
#define SCTLR_CP15BEN 0x00000020 /* CP15 barrier operations: 1 = enabled (default), 0 = disabled */
#define SCTLR_B 0x00000080 /* Endianness: 0 = default, do not modify */
#define SCTLR_SW 0x00000400 /* SWP/SWPB instructions: 0 = disable, 1 = enable */
#define SCTLR_Z 0x00000800 /* Branch prediction: 0 = disable, 1 = enable */
#define SCTLR_I 0x00001000 /* Instruction cache: 0 = disable, 1 = enable */
#define SCTLR_V 0x00002000 /* Exception vectors: 0 = 0x00000000 (configurable), 1 = 0xFFFF0000 (fixed) */
#define SCTLR_RR 0x00004000 /* Cache strategy: 0 = normal, 1 = round-robin */
#define SCTLR_L4 0x00008000 /* PC load reset T-bit: 0 = yes, 1 = no */
#define SCTLR_HA 0x00020000 /* Hardware access flag: 0 = disabled, 1 = enabled */
#define SCTLR_WXN 0x00080000 /* Write permission implies XN: 0 = no, 1 = yes */
#define SCTLR_UWXN 0x00100000 /* Unprivileged write permission implies PL1 XN: 0 = no, 1 = yes */
#define SCTLR_FI 0x00200000 /* Fast interrupts: 0 = normal, 1 = low-latency */
#define SCTLR_U 0x00400000 /* unaligned access: 0 = disabled (default), 1 = enabled */
#define SCTLR_XP 0x00800000 /* subpage AP bits: 0 = enabled, 1 = disabled */
#define SCTLR_VE 0x01000000 /* Interrupt vectors: 0 = standard, 1 = determined by VIC */
#define SCTLR_EE 0x02000000 /* Exception endianness: 0 = little-endian (default), 1 = big-endian */
#define SCTLR_NMFI 0x08000000 /* Non-maskable FIQ: 0 = disabled, 1 = enabled */
#define SCTLR_TRE 0x10000000 /* TEX attributes remap: 0 = disabled, 1 = enabled */
#define SCTLR_AFE 0x20000000 /* AP[0] = Access Flag: 0 = disabled, 1 = enabled */
#define SCTLR_TE 0x40000000 /* Instruction set state for exceptions: 0 = ARM (default), 1 = Thumb */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __SCTLR_H_INCLUDED */

View File

@ -0,0 +1,69 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __SEG_H_INCLUDED
#define __SEG_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
#ifndef __ASM__
#include <comrogue/types.h>
#ifdef __COMROGUE_PRESTART__
#define SEG_INIT_CODE __attribute__((__section__(".prestart.text")))
#define SEG_INIT_DATA __attribute__((__section__(".prestart.data")))
#define SEG_INIT_RODATA __attribute__((__section__(".prestart.rodata")))
#define SEG_RODATA SEG_INIT_RODATA
#define SEG_LIB_CODE SEG_INIT_CODE
#define SEG_LIB_RODATA SEG_INIT_RODATA
#else
#define SEG_INIT_CODE __attribute__((__section__(".init.text")))
#define SEG_INIT_DATA __attribute__((__section__(".init.data")))
#define SEG_INIT_RODATA __attribute__((__section__(".init.rodata")))
#define SEG_RODATA __attribute__((__section__(".rodata")))
#define SEG_LIB_CODE __attribute__((__section__(".lib.text")))
#define SEG_LIB_RODATA __attribute__((__section__(".lib.rodata")))
#endif /* __COMROGUE_PRESTART__ */
#define DECLARE_INIT_STRING8_CONST(name, value) const CHAR SEG_INIT_RODATA name [] = value
#define DECLARE_LIB_STRING8_CONST(name, value) const CHAR SEG_LIB_RODATA name [] = value
#define DECLARE_STRING8_CONST(name, value) const CHAR SEG_RODATA name [] = value
#endif /* __ASM__ */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __SEG_H_INCLUDED */

View File

@ -0,0 +1,200 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __STARTUP_H_INCLUDED
#define __STARTUP_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
#ifdef __COMROGUE_PRESTART__
/*------------------------------------------------
* ATAG data passed to the kernel at startup time
*------------------------------------------------
*/
/* The different ATAG types. */
#define ATAGTYPE_NONE 0 /* none - end of list */
#define ATAGTYPE_CORE 0x54410001 /* core - this one must be first */
#define ATAGTYPE_MEM 0x54410002 /* memory */
#define ATAGTYPE_VIDEOTEXT 0x54410003 /* text-mode video */
#define ATAGTYPE_RAMDISK 0x54410004 /* RAM disk */
#define ATAGTYPE_INITRD2 0x54420005 /* compressed initial RAM disk */
#define ATAGTYPE_SERIAL 0x54410006 /* serial number */
#define ATAGTYPE_REVISION 0x54410007 /* revision */
#define ATAGTYPE_VIDEOLFB 0x54410008 /* linear framebuffer video */
#define ATAGTYPE_CMDLINE 0x54410009 /* command line */
/* Flags for the core ATAG's uiFlags member. */
#define ATAG_COREFLAG_READONLY 0x00000001 /* read only */
#define ATAG_RAMDISKFLAG_LOAD 0x00000001
#define ATAG_RAMDISKFLAG_PROMPT 0x00000002
#endif /* __COMROGUE_PRESTART__ */
#ifndef __ASM__
#include <comrogue/types.h>
#ifdef __COMROGUE_PRESTART__
/* Header of all ATAGs. */
typedef struct tagATAG_HEADER {
UINT32 uiSize; /* size of the tag, in 32-bit words */
UINT32 uiTag; /* the tag indicator */
} ATAG_HEADER, *PATAG_HEADER;
/* Core ATAG - must be first in the list */
typedef struct tagATAG_CORE {
ATAG_HEADER hdr; /* header */
UINT32 uiFlags; /* core flags, see above */
UINT32 uiPageSize; /* system page size in bytes */
UINT32 uiRootDevice; /* root device number */
} ATAG_CORE, *PATAG_CORE;
/* Memory ATAG */
typedef struct tagATAG_MEM {
ATAG_HEADER hdr; /* header */
UINT32 uiSize; /* size of memory */
PHYSADDR paStart; /* physical address of start of memory */
} ATAG_MEM, *PATAG_MEM;
/* Text-mode video ATAG */
typedef struct tagATAG_VIDEOTEXT {
ATAG_HEADER hdr; /* header */
BYTE bWidth; /* display width */
BYTE bHeight; /* display height */
UINT16 uiVideoPage;
BYTE bVideoMode;
BYTE bColumns;
UINT16 uiEGABX;
BYTE bLines;
BYTE bIsVGA;
UINT16 uiPoints;
} ATAG_VIDEOTEXT, *PATAG_VIDEOTEXT;
/* RAM disk ATAG */
typedef struct tagATAG_RAMDISK {
ATAG_HEADER hdr; /* header */
UINT32 uiFlags; /* RAM disk flags, see above */
UINT32 uiSize; /* size of ramdisk in kB */
UINT32 uiStartBlock; /* starting block of ramdisk */
} ATAG_RAMDISK, *PATAG_RAMDISK;
/* Initial ramdisk image ATAG */
typedef struct tagATAG_INITRD2 {
ATAG_HEADER hdr; /* header */
PHYSADDR paStart; /* physical address of compressed ramdisk image */
UINT32 uiSize; /* size of compressed ramdisk image in bytes */
} ATAG_INITRD2, *PATAG_INITRD2;
/* Serial number ATAG */
typedef struct tagATAG_SERIAL {
ATAG_HEADER hdr; /* header */
UINT32 uiSerialNumberLow; /* low word of serial number */
UINT32 uiSerialNumberHigh; /* high word of serial number */
} ATAG_SERIAL, *PATAG_SERIAL;
/* Revision number ATAG */
typedef struct tagATAG_REVISION {
ATAG_HEADER hdr; /* header */
UINT32 uiRevision; /* revision number */
} ATAG_REVISION, *PATAG_REVISION;
/* Linear framebuffer video ATAG */
typedef struct tagATAG_VIDEOLFB {
ATAG_HEADER hdr; /* header */
UINT16 uiFrameBufferWidth;
UINT16 uiFrameBufferHeight;
UINT16 uiFrameBufferDepth;
UINT16 uiFrameBufferLineLength;
UINT32 uiFrameBufferBase;
UINT32 uiFrameBufferSize;
BYTE bRedSize;
BYTE bRedPos;
BYTE bGreenSize;
BYTE bGreenPos;
BYTE bBlueSize;
BYTE bBluePos;
BYTE bReservedSize;
BYTE bReservedPos;
} ATAG_VIDEOLFB, *PATAG_VIDEOLFB;
/* Command line ATAG */
typedef struct tagATAG_CMDLINE {
ATAG_HEADER hdr; /* header */
CHAR szCommandLine[1]; /* text of command line, null-terminated */
} ATAG_CMDLINE, *PATAG_CMDLINE;
/* Macro to advance to the next ATAG */
#define kiNextATAG(p) ((PATAG_HEADER)(((PUINT32)(p)) + ((PATAG_HEADER)(p))->uiSize))
#endif /* __COMROGUE_PRESTART__ */
/*----------------------------------------------------------------
* The startup information buffer filled in by the prestart code.
*----------------------------------------------------------------
*/
typedef struct tagSTARTUP_INFO {
/* start of structure accessed from ASM - be careful here */
UINT32 cb; /* number of bytes in this structure */
PHYSADDR paTTB; /* physical address of the TTB */
KERNADDR kaTTB; /* kernel address of the TTB */
/* end of structure accessed from ASM - be careful here */
UINT32 uiMachineType; /* machine type indicator */
UINT32 uiRevision; /* board revision */
UINT32 uiSerialNumber; /* serial number */
UINT32 cpgSystemTotal; /* total number of memory pages in the system */
UINT32 cpgSystemAvail; /* available memory pages in the system after GPU takes its bite */
UINT32 cpgTTBGap; /* number of pages in the "gap" between the end of kernel and TTB */
PHYSADDR paMPDB; /* physical address of the Master Page Database */
KERNADDR kaMPDB; /* kernel address of the Master Page Database */
UINT32 cpgMPDB; /* number of pages we allocated for Master Page Database */
PHYSADDR paFirstPageTable; /* physical address of the first page table */
UINT32 cpgPageTables; /* number of pages we allocated for page tables */
UINT32 ctblFreeOnLastPage; /* number of page tables free on last page (0 or 1) */
PHYSADDR paFirstFree; /* first free physical address after initial page tables */
KERNADDR vmaFirstFree; /* first free virtual memory address after mapped TTB */
UINT32 uiEMMCClockFreq; /* EMMC clock frequency */
PHYSADDR paVCMem; /* VideoCore memory base */
UINT32 cbVCMem; /* VideoCore memory size in bytes */
UINT16 cxFBWidth; /* frame buffer width in pixels */
UINT16 cyFBHeight; /* frame buffer height in pixels */
BYTE abMACAddress[6]; /* MAC address of the network interface */
} STARTUP_INFO, *PSTARTUP_INFO;
#endif /* __ASM__ */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __STARTUP_H_INCLUDED */

View File

@ -0,0 +1,112 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __TRACE_H_INCLUDED
#define __TRACE_H_INCLUDED
#ifdef __COMROGUE_INTERNALS__
#ifndef __ASM__
#include <stdarg.h>
#include <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/compiler_macros.h>
#include <comrogue/internals/seg.h>
/*------------------------
* System trace functions
*------------------------
*/
CDECL_BEGIN
#ifdef __COMROGUE_PRESTART__
extern void ETrInit(void);
extern void ETrWriteChar8(CHAR c);
extern void ETrWriteString8(PCSTR psz);
extern void ETrWriteWord(UINT32 uiValue);
extern void ETrDumpWords(PUINT32 puiWords, UINT32 cWords);
extern void ETrAssertFailed(PCSTR pszFile, INT32 nLine);
extern void ETrInfiniBlink(void);
#define ASSERT_FAIL_FUNC ETrAssertFailed
#else
extern void TrInit(void);
extern void TrWriteChar8(CHAR c);
extern void TrWriteString8(PCSTR str);
extern void TrWriteWord(UINT32 uiValue);
extern HRESULT TrVPrintf8(PCSTR pszFormat, va_list pargs);
extern HRESULT TrPrintf8(PCSTR pszFormat, ...);
extern void TrAssertFailed(PCSTR pszFile, INT32 nLine);
extern void TrInfiniBlink(void);
#define ASSERT_FAIL_FUNC TrAssertFailed
#endif /* __COMROGUE_PRESTART__ */
CDECL_END
/*------------------------------------------------
* Macro definitions for the assert functionality
*------------------------------------------------
*/
#ifndef NDEBUG
#define THIS_FILE __FILE__
#if defined(__COMROGUE_PRESTART__) || defined(__COMROGUE_INIT__)
#define DECLARE_THIS_FILE static DECLARE_INIT_STRING8_CONST(THIS_FILE, __FILE__);
#else
#define DECLARE_THIS_FILE static DECLARE_STRING8_CONST(THIS_FILE, __FILE__);
#endif
#define ASSERT(x) ((x) ? (void)0 : ASSERT_FAIL_FUNC(THIS_FILE, __LINE__))
#define VERIFY(x) ASSERT(x)
#else
#define DECLARE_THIS_FILE
#define ASSERT(x) ((void)0)
#define VERIFY(x) ((void)(x))
#endif /* NDEBUG */
#endif /* __ASM__ */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __TRACE_H_INCLUDED */

57
include/comrogue/intlib.h Normal file
View File

@ -0,0 +1,57 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __INTLIB_H_INCLUDED
#define __INTLIB_H_INCLUDED
#ifndef __ASM__
#include <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/compiler_macros.h>
#define intMin(x, y) (((x) < (y)) ? (x) : (y))
#define intMax(x, y) (((x) > (y)) ? (x) : (y))
typedef struct tagLDIV {
INT64 quot;
INT64 rem;
} LDIV, *PLDIV;
CDECL_BEGIN
extern HRESULT IntLDiv(PLDIV pResult, INT64 num, INT64 denom);
CDECL_END
#endif /* __ASM__ */
#endif /* __INTLIB_H_INCLUDED */

View File

@ -0,0 +1,90 @@
#ifndef __OBJECT_DEFINITION_MACROS_H_INCLUDED
#define __OBJECT_DEFINITION_MACROS_H_INCLUDED
#ifndef __ASM__
#include <comrogue/compiler_macros.h>
#include <comrogue/types.h>
/*------------------------------------------------------------------------------------
* GUID definition macros which define either a GUID or an external reference to one,
* controlled by symbol INITGUID
*------------------------------------------------------------------------------------
*/
#ifndef GUIDATTR
#ifdef __COMROGUE_INTERNALS__
#include <comrogue/internals/seg.h>
#define GUIDATTR SEG_RODATA
#else
#define GUIDATTR
#endif /* __COMROGUE_INTERNALS__ */
#endif /* GUIDATTR */
#ifdef INITGUID
#define DEFINE_UUID_TYPE(typ, name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const typ GUIDATTR name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
#else
#define DEFINE_UUID_TYPE(typ, name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C extern const typ GUIDATTR name
#endif /* INITGUID */
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_UUID_TYPE(GUID, name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
#define DEFINE_IID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_UUID_TYPE(IID, name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
#define DEFINE_CLSID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
DEFINE_UUID_TYPE(CLSID, name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
/*----------------------------------------------------------------------------------------
* Macros used in the auto-generated object declarations, controlled by symbol CINTERFACE
*----------------------------------------------------------------------------------------
*/
#if !defined(__cplusplus) && !defined(CINTERFACE)
#define CINTERFACE
#endif
#define interface struct
#ifdef CINTERFACE
#define STDMETHOD_(name, typ) typ (*name)
#define STDMETHOD(name) HRESULT (*name)
#define THIS_(typ) typ *pThis,
#define THIS(typ) typ *pThis
#define PURE
#define END_METHODS
#define INHERIT_METHODS(sym) sym
#define BEGIN_INTERFACE(typ) \
struct typ ## VTable {
#define BEGIN_INTERFACE_(typ, parent) \
struct typ ## VTable {
#define END_INTERFACE(typ) }; \
typedef interface typ { const struct typ ## VTable *pVTable; } typ;
#else
#define STDMETHOD_(name, typ) typ name
#define STDMETHOD(name) HRESULT name
#define THIS_(typ)
#define THIS(typ)
#define PURE = 0
#define END_METHODS
#define INHERIT_METHODS(sym)
#define BEGIN_INTERFACE(typ) \
interface typ {
#define BEGIN_INTERFACE_(typ, parent) \
interface typ : parent {
#define END_INTERFACE(typ) };
#endif /* CINTERFACE */
#endif /* __ASM__ */
#endif /* __OBJECT_DEFINITION_MACROS_H_INCLUDED */

97
include/comrogue/scode.h Normal file
View File

@ -0,0 +1,97 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __SCODE_H_INCLUDED
#define __SCODE_H_INCLUDED
#include <comrogue/types.h>
/*-------------------------------------------------------------------
* Status codes are defined as follows:
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |S| Facility | Code |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 9 8 7 6 5 4 3 2 1 0
* 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
*
* S = Severity: 0 = success, 1 = error
* Facility = Facility code
* Code = Specific error code
*-------------------------------------------------------------------
*/
/* Severity codes */
#define SEVERITY_SUCCESS 0x00000000
#define SEVERITY_ERROR 0x80000000
/* Facility codes - compatible with M$ */
#define FACILITY_NULL 0
#define FACILITY_STORAGE 3
#define FACILITY_ITF 4
#define FACILITY_COMROGUE 7
#define FACILITY_STRFORMAT 0x333
#ifndef __ASM__
#include <comrogue/types.h>
#define SUCCEEDED(s) (((s) & SEVERITY_ERROR) == 0)
#define FAILED(s) (((s) & SEVERITY_ERROR) != 0)
#define SCODE_FACILITY(s) (((s) >> 16) & 0x7FFF)
#define SCODE_CODE(s) ((s) & 0xFFFF)
#define MAKE_SCODE(sev, fac, err) ((SCODE)((sev) | (((fac) & 0x7FFF) << 16) | ((err) & 0xFFFF)))
#define SCODE_CAST(x) ((SCODE)(x))
#else
#define SCODE_CAST(x) x
#endif /* __ASM__ */
#define S_OK SCODE_CAST(0x00000000) /* OK return */
#define S_FALSE SCODE_CAST(0x00000001) /* "False" return */
#define E_NOTIMPL SCODE_CAST(0x80000001) /* not implemented */
#define E_OUTOFMEMORY SCODE_CAST(0x80000002) /* out of memory */
#define E_INVALIDARG SCODE_CAST(0x80000003) /* invalid argument */
#define E_NOINTERFACE SCODE_CAST(0x80000004) /* no such interface */
#define E_POINTER SCODE_CAST(0x80000005) /* invalid pointer */
#define E_HANDLE SCODE_CAST(0x80000006) /* invalid handle */
#define E_ABORT SCODE_CAST(0x80000007) /* aborted operation */
#define E_FAIL SCODE_CAST(0x80000008) /* unspecified failure */
#define E_ACCESSDENIED SCODE_CAST(0x80000009) /* access denied */
#define E_PENDING SCODE_CAST(0x8000000A) /* data not yet available */
#define E_UNEXPECTED SCODE_CAST(0x8000FFFF) /* unexpected error */
#endif /* __SCODE_H_INCLUDED */

62
include/comrogue/str.h Normal file
View File

@ -0,0 +1,62 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __STR_H_INCLUDED
#define __STR_H_INCLUDED
#ifndef __ASM__
#include <stdarg.h>
#include <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/compiler_macros.h>
/*------------------
* String functions
*------------------
*/
typedef HRESULT (*PFNFORMAT8)(PPVOID, PCCHAR, UINT32);
CDECL_BEGIN
extern PVOID StrCopyMem(PVOID pDest, PCVOID pSrc, INT32 nBytes);
extern BOOL StrIsDigit8(CHAR ch);
extern INT32 StrLength8(PCSTR psz);
extern PCHAR StrChar8(PCSTR psz, INT32 ch);
extern HRESULT StrFormatV8(PFNFORMAT8 pfnFormat, PVOID pArg, PCSTR pszFormat, va_list pargs);
CDECL_END
#endif /* __ASM__ */
#endif /* __STR_H_INCLUDED */

96
include/comrogue/types.h Normal file
View File

@ -0,0 +1,96 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#ifndef __TYPES_H_INCLUDED
#define __TYPES_H_INCLUDED
/* Integral limit values */
#define INT16_MIN 0x8000
#define INT16_MAX 0x7FFF
#define UINT16_MIN 0
#define UINT16_MAX 0xFFFF
#define INT32_MIN 0x80000000
#define INT32_MAX 0x7FFFFFFF
#define UINT32_MIN 0
#define UINT32_MAX 0xFFFFFFFF
#define INT64_MIN 0x8000000000000000
#define INT64_MAX 0x7FFFFFFFFFFFFFFF
#define UINT64_MIN 0
#define UINT64_MAX 0xFFFFFFFFFFFFFFFF
#define INT_PTR_MIN INT32_MIN
#define INT_PTR_MAX INT32_MAX
#define UINT_PTR_MIN UINT32_MIN
#define UINT_PTR_MAX UINT32_MAX
/* Number of bits */
#define INT16_BITS 16
#define UINT16_BITS 16
#define INT32_BITS 32
#define UINT32_BITS 32
#define INT64_BITS 64
#define UINT64_BITS 64
/* Boolean values */
#define TRUE 1
#define FALSE 0
/* NULL value */
#ifndef NULL
#define NULL 0
#endif
#ifndef __ASM__
/* The basic types referenced by object_types.h. */
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#include <comrogue/object_types.h>
#define MAKEBOOL(val) ((val) ? TRUE : FALSE)
#ifdef __COMROGUE_INTERNALS__
/* Internal system types */
typedef UINT32 PHYSADDR; /* physical address */
typedef UINT32 KERNADDR; /* kernel address */
#endif /* __COMROGUE_INTERNALS__ */
#endif /* __ASM__ */
#endif /* __TYPES_H_INCLUDED */

77
kernel/Makefile Normal file
View File

@ -0,0 +1,77 @@
#
# This file is part of the COMROGUE Operating System for Raspberry Pi
#
# Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
# All rights reserved.
#
# This program is free for commercial and non-commercial use as long as the following conditions are
# adhered to.
#
# Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
# in the code are not to be removed.
#
# 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.
#
# THIS SOFTWARE IS 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 HOLDER 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.
#
# "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
MAKEFLAGS += -rR
ARMDIR ?= /opt/gnuarm/bin
ARMPREFIX ?= arm-none-eabi
CC = $(ARMDIR)/$(ARMPREFIX)-gcc
CPP = $(ARMDIR)/$(ARMPREFIX)-cpp
AS = $(ARMDIR)/$(ARMPREFIX)-as
LD = $(ARMDIR)/$(ARMPREFIX)-ld
OBJDUMP = $(ARMDIR)/$(ARMPREFIX)-objdump
OBJCOPY = $(ARMDIR)/$(ARMPREFIX)-objcopy
DEFS = -D__COMROGUE_INTERNALS__
INCLUDES = -I../include -I../idl
CFLAGS = $(INCLUDES) -mabi=aapcs -mfloat-abi=hard -mcpu=arm1176jzf-s -Wall -O2 \
-nostdlib -nostartfiles -ffreestanding $(DEFS)
AFLAGS = -mcpu=arm1176jzf-s -mfloat-abi=hard
ASM_CPP_FLAGS = $(INCLUDES) $(DEFS) -D__ASM__
PRESTART_OBJS = prestart.o early_trace.o collect_startup.o early_mm.o
LIB_OBJS = divide.o qdivrem.o intlib.o str.o strcopymem.o
RES_OBJS = lowlevel.o trace.o
INIT_OBJS = start.o kistart.o
all: kernel.img
comrogue-kernel.elf : $(PRESTART_OBJS) $(LIB_OBJS) $(RES_OBJS) $(INIT_OBJS) comrogue-kernel.lds
$(CPP) $(ASM_CPP_FLAGS) -P -o comrogue-kernel.lds.parsed comrogue-kernel.lds
$(LD) -T comrogue-kernel.lds.parsed $(PRESTART_OBJS) $(LIB_OBJS) $(RES_OBJS) \
$(INIT_OBJS) -o comrogue-kernel.elf
kernel.img : comrogue-kernel.elf
$(OBJDUMP) -D comrogue-kernel.elf > comrogue-kernel.list
$(OBJDUMP) -t comrogue-kernel.elf > comrogue-kernel.syms
sort comrogue-kernel.syms > comrogue-kernel.syms.sorted
$(OBJCOPY) comrogue-kernel.elf -O binary kernel.img
%.o: %.S
$(CPP) $(ASM_CPP_FLAGS) -o $(basename $<).s $<
$(AS) $(AFLAGS) -o $@ $(basename $<).s
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
-rm *.o *.s kernel.img comrogue-kernel.elf comrogue-kernel.lds.parsed comrogue-kernel.list \
comrogue-kernel.syms*

245
kernel/collect_startup.c Normal file
View File

@ -0,0 +1,245 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/startup.h>
/* The startup information buffer. */
SEG_INIT_DATA static STARTUP_INFO startup_info = {
.cb = sizeof(STARTUP_INFO),
.paTTB = 0,
.kaTTB = 0,
.cpgTTBGap = 0,
.paMPDB = 0,
.kaMPDB = 0,
.cpgMPDB = 0,
.paFirstPageTable = 0,
.cpgPageTables = 0,
.ctblFreeOnLastPage = 0,
.paFirstFree = 0,
.vmaFirstFree = 0
};
/*
* Find a variable by name on the command line.
*
* Parameters:
* - pszCmdLine = Command-line pointer.
* - pszVariableName = Name of variable to search for.
*
* Returns:
* NULL if the variable was not found, otherwise a pointer to the first character in the command line
* following the variable name and associated = sign (first character of the value).
*/
SEG_INIT_CODE static PCSTR find_variable(PCSTR pszCmdLine, PCSTR pszVariableName)
{
register PCSTR p = pszCmdLine;
register PCSTR p1, q;
while (*p)
{
for (; *p && (*p != *pszVariableName); p++) ;
if (*p)
{
for (p1 = p, q = pszVariableName; *p1 && *q && (*p1 == *q); p1++, q++) ;
if (!(*q) && *p1 == '=')
return p1 + 1;
p++;
}
}
return NULL;
}
/*
* Returns whether a character is a valid digit.
*
* Parameters:
* - ch = The character to be tested.
* - base = The base of the number being converted.
*
* Returns:
* TRUE if the character is a valid digit, FALSE otherwise.
*/
SEG_INIT_CODE static BOOL is_valid_digit(CHAR ch, UINT32 base)
{
register UINT32 nbase;
if (base > 10)
{
if ((ch >= 'a') && (ch < ('a' + base - 10)))
return TRUE;
if ((ch >= 'A') && (ch < ('A' + base - 10)))
return TRUE;
}
nbase = (base > 10) ? 10 : base;
if ((ch >= '0') && (ch < ('0' + nbase)))
return TRUE;
return FALSE;
}
/*
* Decodes a number in a command-line parameter. Decoding stops at the first character that is not a valid digit.
*
* Parameters:
* - pVal = Pointer to the value in the command line.
* - base = Base of the number to convert. If this is 16, the decoder will skip over a "0x" or "0X" prefix
* of the value, if one exists.
*
* Returns:
* The converted numeric value.
*/
SEG_INIT_CODE static UINT32 decode_number(PCSTR pVal, UINT32 base)
{
register UINT32 accum = 0;
register UINT32 digit;
if ((base == 16) && (*pVal == '0') && ((*(pVal + 1) == 'x') || (*(pVal + 1) == 'X')))
pVal += 2;
while (is_valid_digit(*pVal, base))
{
if (*pVal >= 'a')
digit = (*pVal - 'a') + 10;
else if (*pVal >= 'A')
digit = (*pVal - 'A') + 10;
else
digit = (*pVal - '0');
accum = accum * base + digit;
pVal++;
}
return accum;
}
/*
* Parses the command line passed in via the ATAGS and extracts certain values to the startup info
* data structure.
*
* Parameters:
* - pszCmdLine = Pointer to the command line.
*
* Returns:
* Nothing.
*
* Side effects:
* Modifies the "startup_info" structure.
*/
SEG_INIT_CODE static void parse_cmdline(PCSTR pszCmdLine)
{
static DECLARE_INIT_STRING8_CONST(szFBWidth, "bcm2708_fb.fbwidth");
static DECLARE_INIT_STRING8_CONST(szFBHeight, "bcm2708_fb.fbheight");
static DECLARE_INIT_STRING8_CONST(szRevision, "bcm2708.boardrev");
static DECLARE_INIT_STRING8_CONST(szSerial, "bcm2708.serial");
static DECLARE_INIT_STRING8_CONST(szMACAddr, "smsc95xx.macaddr");
static DECLARE_INIT_STRING8_CONST(szEMMCFreq, "sdhci-bcm2708.emmc_clock_freq");
static DECLARE_INIT_STRING8_CONST(szVCMemBase, "vc_mem.mem_base");
static DECLARE_INIT_STRING8_CONST(szVCMemSize, "vc_mem.mem_size");
register PCSTR p;
register int i;
p = find_variable(pszCmdLine, szFBWidth);
startup_info.cxFBWidth = (UINT16)(p ? decode_number(p, 10) : 0);
p = find_variable(pszCmdLine, szFBHeight);
startup_info.cyFBHeight = (UINT16)(p ? decode_number(p, 10) : 0);
p = find_variable(pszCmdLine, szRevision);
startup_info.uiRevision = (p ? decode_number(p, 16) : 0);
p = find_variable(pszCmdLine, szSerial);
startup_info.uiSerialNumber = (p ? decode_number(p, 16) : 0);
p = find_variable(pszCmdLine, szMACAddr);
if (p)
{
for (i=0; i<6; i++)
{
startup_info.abMACAddress[i] = (BYTE)decode_number(p, 16);
p += 3;
}
}
else
{
for (i=0; i<6; i++)
startup_info.abMACAddress[i] = 0;
}
p = find_variable(pszCmdLine, szEMMCFreq);
startup_info.uiEMMCClockFreq = (p ? decode_number(p, 10) : 0);
p = find_variable(pszCmdLine, szVCMemBase);
startup_info.paVCMem = (PHYSADDR)(p ? decode_number(p, 16) : 0);
p = find_variable(pszCmdLine, szVCMemSize);
startup_info.cbVCMem = (p ? decode_number(p, 16) : 0);
startup_info.cpgSystemTotal = startup_info.cbVCMem >> SYS_PAGE_BITS;
}
/*
* Collects startup information in an init-data buffer and returns a pointer to that buffer.
*
* Parameters:
* - always0 = Always 0.
* - uiMachineType = Machine type constant.
* - pAtags = Pointer to ATAGS data set up before kernel was started.
*
* Returns:
* A pointer to the assembled STARTUP_INFO data structure.
*
* Side effects:
* Modifies the "startup_info" structure, which it returns a pointer to.
*/
SEG_INIT_CODE PSTARTUP_INFO KiCollectStartupInfo(UINT32 always0, UINT32 uiMachineType, PATAG_HEADER pAtags)
{
/* Fill in the information we can calculate right away. */
startup_info.uiMachineType = uiMachineType;
/* Scan the ATAG headers to determine what other info to include. */
while (pAtags->uiTag != ATAGTYPE_NONE)
{
switch (pAtags->uiTag)
{
case ATAGTYPE_CORE:
/* nothing really useful in this block */
break;
case ATAGTYPE_MEM:
/* fill in total number of available system memory pages */
startup_info.cpgSystemAvail = ((PATAG_MEM)pAtags)->uiSize >> SYS_PAGE_BITS;
break;
case ATAGTYPE_CMDLINE:
parse_cmdline(((PATAG_CMDLINE)pAtags)->szCommandLine);
break;
default:
/* no other ATAG types are seen on Raspberry Pi */
break;
}
pAtags = kiNextATAG(pAtags);
}
return &startup_info;
}

134
kernel/comrogue-kernel.lds Normal file
View File

@ -0,0 +1,134 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/layout.h>
ENTRY(COMROGUEPrestart)
SECTIONS
{
/* all these are prestart code that runs in low memory with MMU off */
/* space is reclaimed once the kernel begins operation in high memory with MMU on */
.prestart.text PHYSADDR_LOAD : AT (PHYSADDR_LOAD) {
paPrestartCode = .;
*(.prestartHEAD.text) /* must be first! */
*(.prestart.text)
*(.prestart.rodata)
*(.prestart.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgPrestartCode = (. - paPrestartCode) >> SYS_PAGE_BITS;
paPrestartData = .;
.prestart.data : AT(paPrestartData) {
*(.prestart.data)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgPrestartData = (. - paPrestartData) >> SYS_PAGE_BITS;
cpgPrestartTotal = . >> SYS_PAGE_BITS;
paLibraryCode = .;
/* kernel library code, in high memory mapped to be visible to user processes */
.lib.text VMADDR_LIBRARY_FENCE : AT (paLibraryCode) {
vmaLibraryCode = .;
*(.lib.text)
*(.lib.rodata)
*(.lib.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgLibraryCode = (. - vmaLibraryCode) >> SYS_PAGE_BITS;
paKernelCode = paLibraryCode + (. - vmaLibraryCode);
/* kernel resident code, runs in high memory with MMU on */
.text VMADDR_KERNEL_FENCE : AT(paKernelCode) {
vmaKernelCode = .;
*(.text)
*(.rodata)
*(.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgKernelCode = (. - vmaKernelCode) >> SYS_PAGE_BITS;
paKernelData = paKernelCode + (. - vmaKernelCode);
.data : AT(paKernelData) {
vmaKernelData = .;
*(.data)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgKernelData = (. - vmaKernelData) >> SYS_PAGE_BITS;
paKernelBss = paKernelData + (. - vmaKernelData);
.bss : AT(paKernelBss) {
vmaKernelBss = .;
*(.bss)
*(COMMON)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgKernelBss = (. - vmaKernelBss) >> SYS_PAGE_BITS;
paInitCode = paKernelBss + (. - vmaKernelBss);
/* kernel one-time initialization code, runs in high memory with MMU on */
/* space is reclaimed once the kernel finishes initialization */
.init.text : AT(paInitCode) {
vmaInitCode = .;
*(.initHEAD.text) /* must be first! */
*(.init.text)
*(.init.rodata)
*(.init.rodata.*)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgInitCode = (. - vmaInitCode) >> SYS_PAGE_BITS;
paInitData = paInitCode + (. - vmaInitCode);
.init.data : AT(paInitData) {
vmaInitData = .;
*(.init.data)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgInitData = (. - vmaInitData) >> SYS_PAGE_BITS;
paInitBss = paInitData + (. - vmaInitData);
.init.bss : AT(paInitBss) {
vmaInitBss = .;
*(.init.bss)
. = ALIGN(SYS_PAGE_SIZE);
}
cpgInitBss = (. - vmaInitBss) >> SYS_PAGE_BITS;
paFirstFree = paInitBss + (. - vmaInitBss);
vmaFirstFree = .;
/DISCARD/ : {
*(.comment)
*(.note*)
*(.ARM.attributes)
}
}

479
kernel/divide.S Normal file
View File

@ -0,0 +1,479 @@
/*
* Portions of this file are subject to the following notices:
*
* Copyright (C) 2012 Andrew Turner
* All rights reserved.
*
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas of 3am Software Foundry.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that 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.
*/
/* Derived from FreeBSD libkern divsi3.S, uldivmod.S, and ldivmod.S, munged by Erbo to COMROGUE standards */
.section ".lib.text"
.globl __aeabi_uidiv
.globl __aeabi_uidivmod
__aeabi_uidiv:
__aeabi_uidivmod:
eor r0, r1, r0 /* r0 = r0 / r1; r1 = r0 % r1 */
eor r1, r0, r1
eor r0, r1, r0 /* r0 = r1 / r0; r1 = r1 % r0 */
cmp r0, #1
bcc .L_overflow
beq .L_divide_l0
mov ip, #0
movs r1, r1
bpl .L_divide_l1
orr ip, ip, #0x20000000 /* indicates r1 is negative */
movs r1, r1, lsr #1
orrcs ip, ip, #0x10000000 /* indicates bit 0 of r1 */
b .L_divide_l1
.L_divide_l0:
mov r0, r1 /* r0 == 1 */
mov r1, #0
bx lr
.globl __aeabi_idiv
.globl __aeabi_idivmod
__aeabi_idiv:
__aeabi_idivmod:
eor r0, r1, r0 /* r0 = r0 / r1; r1 = r0 % r1 */
eor r1, r0, r1
eor r0, r1, r0 /* r0 = r1 / r0; r1 = r1 % r0 */
cmp r0, #1
bcc .L_overflow
beq .L_divide_l0
ands ip, r0, #0x80000000
rsbmi r0, r0, #0
ands r2, r1, #0x80000000
eor ip, ip, r2
rsbmi r1, r1, #0
orr ip, r2, ip, lsr #1 /* bit 0x40000000 = negative division, bit 0x80000000 = negative remainder */
.L_divide_l1:
mov r2, #1
mov r3, #0
/*
* If the highest bit of the dividend is set, we have to be
* careful when shifting the divisor. Test this.
*/
movs r1, r1
bpl .L_old_code
/*
* At this point, the highest bit of r1 is known to be set.
* We abuse this below in the tst instructions.
*/
tst r1, r0 /*, lsl #0 */
bmi .L_divide_b1
tst r1, r0, lsl #1
bmi .L_divide_b2
tst r1, r0, lsl #2
bmi .L_divide_b3
tst r1, r0, lsl #3
bmi .L_divide_b4
tst r1, r0, lsl #4
bmi .L_divide_b5
tst r1, r0, lsl #5
bmi .L_divide_b6
tst r1, r0, lsl #6
bmi .L_divide_b7
tst r1, r0, lsl #7
bmi .L_divide_b8
tst r1, r0, lsl #8
bmi .L_divide_b9
tst r1, r0, lsl #9
bmi .L_divide_b10
tst r1, r0, lsl #10
bmi .L_divide_b11
tst r1, r0, lsl #11
bmi .L_divide_b12
tst r1, r0, lsl #12
bmi .L_divide_b13
tst r1, r0, lsl #13
bmi .L_divide_b14
tst r1, r0, lsl #14
bmi .L_divide_b15
tst r1, r0, lsl #15
bmi .L_divide_b16
tst r1, r0, lsl #16
bmi .L_divide_b17
tst r1, r0, lsl #17
bmi .L_divide_b18
tst r1, r0, lsl #18
bmi .L_divide_b19
tst r1, r0, lsl #19
bmi .L_divide_b20
tst r1, r0, lsl #20
bmi .L_divide_b21
tst r1, r0, lsl #21
bmi .L_divide_b22
tst r1, r0, lsl #22
bmi .L_divide_b23
tst r1, r0, lsl #23
bmi .L_divide_b24
tst r1, r0, lsl #24
bmi .L_divide_b25
tst r1, r0, lsl #25
bmi .L_divide_b26
tst r1, r0, lsl #26
bmi .L_divide_b27
tst r1, r0, lsl #27
bmi .L_divide_b28
tst r1, r0, lsl #28
bmi .L_divide_b29
tst r1, r0, lsl #29
bmi .L_divide_b30
tst r1, r0, lsl #30
bmi .L_divide_b31
/*
* instead of:
* tst r1, r0, lsl #31
* bmi .L_divide_b32
*/
b .L_divide_b32
.L_old_code:
cmp r1, r0
bcc .L_divide_b0
cmp r1, r0, lsl #1
bcc .L_divide_b1
cmp r1, r0, lsl #2
bcc .L_divide_b2
cmp r1, r0, lsl #3
bcc .L_divide_b3
cmp r1, r0, lsl #4
bcc .L_divide_b4
cmp r1, r0, lsl #5
bcc .L_divide_b5
cmp r1, r0, lsl #6
bcc .L_divide_b6
cmp r1, r0, lsl #7
bcc .L_divide_b7
cmp r1, r0, lsl #8
bcc .L_divide_b8
cmp r1, r0, lsl #9
bcc .L_divide_b9
cmp r1, r0, lsl #10
bcc .L_divide_b10
cmp r1, r0, lsl #11
bcc .L_divide_b11
cmp r1, r0, lsl #12
bcc .L_divide_b12
cmp r1, r0, lsl #13
bcc .L_divide_b13
cmp r1, r0, lsl #14
bcc .L_divide_b14
cmp r1, r0, lsl #15
bcc .L_divide_b15
cmp r1, r0, lsl #16
bcc .L_divide_b16
cmp r1, r0, lsl #17
bcc .L_divide_b17
cmp r1, r0, lsl #18
bcc .L_divide_b18
cmp r1, r0, lsl #19
bcc .L_divide_b19
cmp r1, r0, lsl #20
bcc .L_divide_b20
cmp r1, r0, lsl #21
bcc .L_divide_b21
cmp r1, r0, lsl #22
bcc .L_divide_b22
cmp r1, r0, lsl #23
bcc .L_divide_b23
cmp r1, r0, lsl #24
bcc .L_divide_b24
cmp r1, r0, lsl #25
bcc .L_divide_b25
cmp r1, r0, lsl #26
bcc .L_divide_b26
cmp r1, r0, lsl #27
bcc .L_divide_b27
cmp r1, r0, lsl #28
bcc .L_divide_b28
cmp r1, r0, lsl #29
bcc .L_divide_b29
cmp r1, r0, lsl #30
bcc .L_divide_b30
.L_divide_b32:
cmp r1, r0, lsl #31
subhs r1, r1,r0, lsl #31
addhs r3, r3,r2, lsl #31
.L_divide_b31:
cmp r1, r0, lsl #30
subhs r1, r1,r0, lsl #30
addhs r3, r3,r2, lsl #30
.L_divide_b30:
cmp r1, r0, lsl #29
subhs r1, r1,r0, lsl #29
addhs r3, r3,r2, lsl #29
.L_divide_b29:
cmp r1, r0, lsl #28
subhs r1, r1,r0, lsl #28
addhs r3, r3,r2, lsl #28
.L_divide_b28:
cmp r1, r0, lsl #27
subhs r1, r1,r0, lsl #27
addhs r3, r3,r2, lsl #27
.L_divide_b27:
cmp r1, r0, lsl #26
subhs r1, r1,r0, lsl #26
addhs r3, r3,r2, lsl #26
.L_divide_b26:
cmp r1, r0, lsl #25
subhs r1, r1,r0, lsl #25
addhs r3, r3,r2, lsl #25
.L_divide_b25:
cmp r1, r0, lsl #24
subhs r1, r1,r0, lsl #24
addhs r3, r3,r2, lsl #24
.L_divide_b24:
cmp r1, r0, lsl #23
subhs r1, r1,r0, lsl #23
addhs r3, r3,r2, lsl #23
.L_divide_b23:
cmp r1, r0, lsl #22
subhs r1, r1,r0, lsl #22
addhs r3, r3,r2, lsl #22
.L_divide_b22:
cmp r1, r0, lsl #21
subhs r1, r1,r0, lsl #21
addhs r3, r3,r2, lsl #21
.L_divide_b21:
cmp r1, r0, lsl #20
subhs r1, r1,r0, lsl #20
addhs r3, r3,r2, lsl #20
.L_divide_b20:
cmp r1, r0, lsl #19
subhs r1, r1,r0, lsl #19
addhs r3, r3,r2, lsl #19
.L_divide_b19:
cmp r1, r0, lsl #18
subhs r1, r1,r0, lsl #18
addhs r3, r3,r2, lsl #18
.L_divide_b18:
cmp r1, r0, lsl #17
subhs r1, r1,r0, lsl #17
addhs r3, r3,r2, lsl #17
.L_divide_b17:
cmp r1, r0, lsl #16
subhs r1, r1,r0, lsl #16
addhs r3, r3,r2, lsl #16
.L_divide_b16:
cmp r1, r0, lsl #15
subhs r1, r1,r0, lsl #15
addhs r3, r3,r2, lsl #15
.L_divide_b15:
cmp r1, r0, lsl #14
subhs r1, r1,r0, lsl #14
addhs r3, r3,r2, lsl #14
.L_divide_b14:
cmp r1, r0, lsl #13
subhs r1, r1,r0, lsl #13
addhs r3, r3,r2, lsl #13
.L_divide_b13:
cmp r1, r0, lsl #12
subhs r1, r1,r0, lsl #12
addhs r3, r3,r2, lsl #12
.L_divide_b12:
cmp r1, r0, lsl #11
subhs r1, r1,r0, lsl #11
addhs r3, r3,r2, lsl #11
.L_divide_b11:
cmp r1, r0, lsl #10
subhs r1, r1,r0, lsl #10
addhs r3, r3,r2, lsl #10
.L_divide_b10:
cmp r1, r0, lsl #9
subhs r1, r1,r0, lsl #9
addhs r3, r3,r2, lsl #9
.L_divide_b9:
cmp r1, r0, lsl #8
subhs r1, r1,r0, lsl #8
addhs r3, r3,r2, lsl #8
.L_divide_b8:
cmp r1, r0, lsl #7
subhs r1, r1,r0, lsl #7
addhs r3, r3,r2, lsl #7
.L_divide_b7:
cmp r1, r0, lsl #6
subhs r1, r1,r0, lsl #6
addhs r3, r3,r2, lsl #6
.L_divide_b6:
cmp r1, r0, lsl #5
subhs r1, r1,r0, lsl #5
addhs r3, r3,r2, lsl #5
.L_divide_b5:
cmp r1, r0, lsl #4
subhs r1, r1,r0, lsl #4
addhs r3, r3,r2, lsl #4
.L_divide_b4:
cmp r1, r0, lsl #3
subhs r1, r1,r0, lsl #3
addhs r3, r3,r2, lsl #3
.L_divide_b3:
cmp r1, r0, lsl #2
subhs r1, r1,r0, lsl #2
addhs r3, r3,r2, lsl #2
.L_divide_b2:
cmp r1, r0, lsl #1
subhs r1, r1,r0, lsl #1
addhs r3, r3,r2, lsl #1
.L_divide_b1:
cmp r1, r0
subhs r1, r1, r0
addhs r3, r3, r2
.L_divide_b0:
tst ip, #0x20000000
bne .L_udivide_l1
mov r0, r3
cmp ip, #0
rsbmi r1, r1, #0
movs ip, ip, lsl #1
bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */
rsbmi r0, r0, #0
bx lr
.L_udivide_l1:
tst ip, #0x10000000
mov r1, r1, lsl #1
orrne r1, r1, #1
mov r3, r3, lsl #1
cmp r1, r0
subhs r1, r1, r0
addhs r3, r3, r2
mov r0, r3
bx lr
.L_overflow:
/* TODO: cause an exception or something? */
mvn r0, #0
bx lr
.globl __aeabi_uldivmod
__aeabi_uldivmod:
push {r4,lr}
sub sp, sp, #8
mov r4, sp
push {r4}
bl __qdivrem
pop {r4}
/*
* The remainder is already on the stack just waiting to be popped
* into r2/r3.
*/
pop {r2-r4,lr}
bx lr
.globl __aeabi_ldivmod
__aeabi_ldivmod:
push {r4-r5, sl, lr}
mov r5, #0 /* r5 = negative indicator */
cmp r3, #0
bge 2f
eor r5, r5, #1 /* flip quotient sign */
bl .Lnegate_b
bcs .Lmaxdenom
2:
cmp r1, #0
/* bge 3f */
eorlt r5, r5, #3 /* flip quotient sign, flip remainder sign */
bllt .Lnegate_a
3:
/*
* Arguments are setup, allocate some stack for the remainder
* and call __qdivrem for the heavy lifting.
*/
sub sp, sp, #8
mov r4, sp /* pointer to remainder */
push {r4}
bl __qdivrem
pop {r4}
teq r5, #0 /* any signs to flip? */
/*
* The quotient is already in the right place and neither value
* needs its sign flipped.
*/
popeq {r2-r5, sl, lr}
bxeq lr
pop {r2, r3}
tst r5, #2 /* does remainder need to be negative? */
bleq .Lnegate_b
tst r5, #1 /* does quotient need to be negative? */
bleq .Lnegate_a
pop {r4-r5, sl, lr}
bx lr
.Lnegate_a:
rsbs r0, r0, #0
rsc r1, r1, #0
bx lr
.Lnegate_b:
rsbs r2, r2, #0
rsc r3, r3, #0
bx lr
.Lmaxdenom:
/*
* We had a carry so the denominator must have INT64_MIN
* Also BLO and BHI never changed values so we can use
* them to see if the numerator has the same value. We
* don't have to worry about sign.
*/
teq r3, r1
teqeq r2, r0
bne 1f
/*
* They were equal, so we return a quotient of 1 and remainder of 0.
*/
mov r0, #1
mov r1, #0
mov r2, #0
mov r3, #0
pop {r4-r5, sl, lr}
bx lr
/*
* Our remainder must be the numerator and our quotient is 0.
*/
1: mov r2, r0
mov r3, r1
mov r0, #0
mov r1, #0
pop {r4-r5, sl, lr}
bx lr

398
kernel/early_mm.c Normal file
View File

@ -0,0 +1,398 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/layout.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/startup.h>
#include <comrogue/internals/trace.h>
#ifdef THIS_FILE
#undef THIS_FILE
DECLARE_THIS_FILE
#endif
/*-----------------------------------------------------------------------------
* Early memory-management code that handles creating the mappings for the TTB
*-----------------------------------------------------------------------------
*/
/* Data stored in here temporarily and reflected back to startup info when we're done. */
SEG_INIT_DATA static PTTB g_pTTB = NULL; /* pointer to TTB */
SEG_INIT_DATA static UINT32 g_cpgForPageTables = 0; /* number of pages being used for page tables */
SEG_INIT_DATA static UINT32 g_ctblFreeonLastPage = 0; /* number of page tables free on last page */
SEG_INIT_DATA static PPAGETAB g_ptblNext = NULL; /* pointer to next free page table */
/*
* Morphs the "flags" bits used for a page table entry in the TTB and for a page entry in the page table
* into the "flags" bits used for a section entry in the TTB.
*
* Parameters:
* - uiTableFlags = Flag bits that would be used for a page table entry in the TTB.
* - uiPageFlags = Flag bits that would be used for a page entry in the page table.
*
* Returns:
* The flag bits that would be used for a section entry in the TTB. If a bit or option is set
* in either uiTableFlags or uiPageFlags, it will be set in the appropriate place in the result.
*/
SEG_INIT_CODE static UINT32 make_section_flags(UINT32 uiTableFlags, UINT32 uiPageFlags)
{
register UINT32 rc = TTBSEC_ALWAYS;
rc |= ((uiTableFlags & TTBPGTBL_PXN) >> 2);
rc |= ((uiTableFlags & TTBPGTBL_NS) << 16);
rc |= (uiTableFlags & TTBPGTBL_DOM_MASK);
rc |= (uiTableFlags & TTBPGTBL_P);
rc |= ((uiPageFlags & PGTBLSM_XN) << 4);
rc |= (uiPageFlags & PGTBLSM_B);
rc |= (uiPageFlags & PGTBLSM_C);
rc |= ((uiPageFlags & PGTBLSM_AP) << 6);
rc |= ((uiPageFlags & PGTBLSM_TEX) << 6);
rc |= ((uiPageFlags & PGTBLSM_APX) << 6);
rc |= ((uiPageFlags & PGTBLSM_S) << 6);
rc |= ((uiPageFlags & PGTBLSM_NG) << 6);
return rc;
}
/*
* Allocates page mapping entries within a single current entry in the TTB.
*
* Parameters:
* - paBase = The page-aligned base physical address to map.
* - pTTBEntry = Pointer to the TTB entry to be used.
* - ndxPage = The "first" index within the current page to use.
* - cpg = The maximum number of pages we want to map. This function will only map as many pages as will
* fit in the current TTB entry, as indicated by ndxPage.
* - uiTableFlags = Flags to be used or verified for the TTB entry.
* - uiPageFlags = Flags to be used for new page table entries.
*
* Returns:
* The number of pages that were actually mapped by this function call, or -1 if there was an error in the mapping.
*
* Side effects:
* May modify the ndxTTB'th entry in the TTB, if it was not previously allocated. May modify the current page
* table that the TTB entry points to, where applicable. If we need to allocate a new page table, may modify the
* global variables g_cpgForPageTables, g_ctblFreeonLastPage, and g_ptblNext.
*/
SEG_INIT_CODE static INT32 alloc_pages(PHYSADDR paBase, PTTB pTTBEntry, INT32 ndxPage, INT32 cpg, UINT32 uiTableFlags,
UINT32 uiPageFlags)
{
INT32 cpgCurrent; /* number of pages we're mapping */
PPAGETAB pTab; /* pointer to current or new page table */
register INT32 i; /* loop counter */
switch (pTTBEntry->data & TTBQUERY_MASK)
{
case TTBQUERY_FAULT: /* not allocated, allocate a new page table for the slot */
if (g_ctblFreeonLastPage == 0)
{
g_cpgForPageTables++;
g_ctblFreeonLastPage = 2;
}
g_ctblFreeonLastPage--;
pTab = g_ptblNext++;
for (i=0; i<SYS_PGTBL_ENTRIES; i++)
{
pTab->pgtbl[i].data = 0; /* blank out the new page table */
pTab->pgaux[i].data = 0;
}
pTTBEntry->data = ((UINT32)pTab) | uiTableFlags; /* poke new entry */
break;
case TTBQUERY_PGTBL: /* existing page table */
if ((pTTBEntry->data & TTBPGTBL_ALLFLAGS) != uiTableFlags)
return -1; /* table flags not compatible */
break;
case TTBQUERY_SEC:
case TTBQUERY_PXNSEC:
/* existing section, deal with this later */
break;
}
/* Figure out how many entries we're going to map. */
cpgCurrent = SYS_PGTBL_ENTRIES - ndxPage; /* total free slots on page */
if (cpg < cpgCurrent)
cpgCurrent = cpg; /* only map up to max requested */
if (pTTBEntry->data & TTBSEC_ALWAYS)
{
/* this is a section, make sure its base address covers this mapping and its flags are compatible */
if ((pTTBEntry->data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags))
return -1;
if ((pTTBEntry->data & TTBSEC_BASE) != (paBase & TTBSEC_BASE))
return -1;
}
else
{
/* fill in entries in the page table */
pTab = (PPAGETAB)(pTTBEntry->data & TTBPGTBL_BASE);
for (i=0; i<cpgCurrent; i++)
{
if ((pTab->pgtbl[ndxPage + i].data & PGQUERY_MASK) != PGQUERY_FAULT)
return -1; /* stepping on existing mapping */
pTab->pgtbl[ndxPage + i].data = paBase | uiPageFlags;
pTab->pgaux[ndxPage + i].data = 0; /* TODO */
paBase += SYS_PAGE_SIZE;
}
}
return cpgCurrent;
}
/*
* Maps a certain number of memory pages beginning at a specified physical address into virtual memory
* beginning at a specified virtual address.
*
* Parameters:
* - paBase = The page-aligned base physical address to map.
* - vmaBase = The page-aligned virtual address to map those pages to.
* - cpg = The number of pages to be mapped.
* - uiTableFlags = Flags to be used or verified for TTB entries.
* - uiPageFlags = Flags to be used for new page table entries.
*
* Returns:
* TRUE if the mapping succeeded, FALSE if it failed.
*
* Side effects:
* May modify unallocated entries in the TTB. May modify any page tables that are pointed to by TTB entries,
* where applicable. If we need to allocate new page tables, may modify the global variables g_cpgForPageTables,
* g_ctblFreeonLastPage, and g_ptblNext.
*/
SEG_INIT_CODE static BOOL map_pages(PHYSADDR paBase, KERNADDR vmaBase, INT32 cpg, UINT32 uiTableFlags,
UINT32 uiPageFlags)
{
static DECLARE_INIT_STRING8_CONST(sz1, "Map ");
static DECLARE_INIT_STRING8_CONST(sz2, "->");
static DECLARE_INIT_STRING8_CONST(sz3, ",cpg=");
static DECLARE_INIT_STRING8_CONST(sz4, ",tf=");
static DECLARE_INIT_STRING8_CONST(sz5, ",pf=");
INT32 ndxTTB = mmVMA2TTBIndex(vmaBase); /* TTB entry index */
INT32 ndxPage = mmVMA2PGTBLIndex(vmaBase); /* starting page entry index */
INT32 cpgCurrent; /* current number of pages mapped */
ETrWriteString8(sz1);
ETrWriteWord(paBase);
ETrWriteString8(sz2);
ETrWriteWord(vmaBase);
ETrWriteString8(sz3);
ETrWriteWord(cpg);
ETrWriteString8(sz4);
ETrWriteWord(uiTableFlags);
ETrWriteString8(sz5);
ETrWriteWord(uiPageFlags);
ETrWriteChar8('\n');
if ((cpg > 0) && (ndxPage > 0))
{
/* We are starting in the middle of a VM page. Map to the end of the VM page. */
cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, ndxPage, cpg, uiTableFlags, uiPageFlags);
if (cpgCurrent < 0)
{
/* ETrWriteChar8('a'); */
return FALSE;
}
/* adjust base physical address, page count, and TTB index */
paBase += (cpgCurrent << SYS_PAGE_BITS);
cpg -= cpgCurrent;
ndxTTB++;
/* N.B.: from this point on ndxPage will be treated as 0 */
}
while (cpg >= SYS_PGTBL_ENTRIES)
{
/* try to map a whole section's worth at a time */
if ((paBase & TTBSEC_BASE) == paBase)
{
/* paBase is section-aligned now as well, we can use a direct 1Mb section mapping */
switch (g_pTTB[ndxTTB].data & TTBQUERY_MASK)
{
case TTBQUERY_FAULT: /* unmapped - map the section */
g_pTTB[ndxTTB].data = paBase | make_section_flags(uiTableFlags, uiPageFlags);
break;
case TTBQUERY_PGTBL: /* collided with a page table */
/* ETrWriteChar8('b'); */
return FALSE;
case TTBQUERY_SEC: /* test existing section */
case TTBQUERY_PXNSEC:
if ((g_pTTB[ndxTTB].data & TTBSEC_ALLFLAGS) != make_section_flags(uiTableFlags, uiPageFlags))
{
/* ETrWriteChar8('c'); */
return FALSE; /* invalid flags */
}
if ((g_pTTB[ndxTTB].data & TTBSEC_BASE) != paBase)
{
/* ETrWriteChar8('d'); */
return FALSE; /* invalid base address */
}
break;
}
cpgCurrent = SYS_PGTBL_ENTRIES; /* we mapped a whole section worth */
}
else
{
/* just map 256 individual pages */
cpgCurrent = alloc_pages(paBase, g_pTTB + ndxTTB, 0, cpg, uiTableFlags, uiPageFlags);
if (cpgCurrent < 0)
{
/* ETrWriteChar8('e'); */
return FALSE;
}
}
/* adjust base physical address, page count, and TTB index */
paBase += (cpgCurrent << SYS_PAGE_BITS);
cpg -= cpgCurrent;
ndxTTB++;
}
if (cpg > 0)
{
/* map the "tail end" onto the next TTB */
if (alloc_pages(paBase, g_pTTB + ndxTTB, 0, cpg, uiTableFlags, uiPageFlags) < 0)
{
/* ETrWriteChar8('f'); */
return FALSE;
}
}
return TRUE;
}
/* External references to symbols defined by the linker script. */
extern char paFirstFree, cpgPrestartTotal, paLibraryCode, vmaLibraryCode, cpgLibraryCode, paKernelCode,
vmaKernelCode, cpgKernelCode, paKernelData, vmaKernelData, cpgKernelData, cpgKernelBss, paInitCode,
vmaInitCode, cpgInitCode, paInitData, vmaInitData, cpgInitData, cpgInitBss, vmaFirstFree;
/*
* Initializes a TTB (used as TTB1 and initially TTB0 as well) with mappings to all the pieces of the kernel and
* to memory-mapped IO, and fills in details in the startup info structure.
*
* Parameters:
* - pstartup - Pointer to startup info structure, which is modified by this function.
*
* Returns:
* - Physical address of the new TTB1.
*
* Side effects:
* Modifies physical memory beyond the end of the kernel to store TTB and page tables. Uses several
* static globals in this module for work space while performing memory mappings.
*/
SEG_INIT_CODE PHYSADDR EMmInit(PSTARTUP_INFO pstartup)
{
static DECLARE_INIT_STRING8_CONST(szTTBAt, "EMmInit: TTB1@");
static DECLARE_INIT_STRING8_CONST(szPageTable, "Page table pages:");
static DECLARE_INIT_STRING8_CONST(szFree, "\nFree last page:");
PHYSADDR paTTB = (PHYSADDR)(&paFirstFree); /* location of the system TTB1 */
UINT32 cbMPDB; /* number of bytes in the MPDB */
register INT32 i; /* loop counter */
/* Locate the appropriate place for TTB1, on a 16K boundary. */
pstartup->cpgTTBGap = 0;
while (paTTB & (SYS_TTB1_SIZE - 1))
{
paTTB += SYS_PAGE_SIZE;
pstartup->cpgTTBGap++;
}
ETrWriteString8(szTTBAt);
ETrWriteWord(paTTB);
ETrWriteChar8('\n');
/* Save off the TTB location and initialize it. */
pstartup->paTTB = paTTB;
g_pTTB = (PTTB)paTTB;
for (i=0; i<SYS_TTB1_ENTRIES; i++)
g_pTTB[i].data = 0;
/* Allocate space for the Master Page Database but do not initialize it. */
pstartup->paMPDB = paTTB + SYS_TTB1_SIZE;
cbMPDB = pstartup->cpgSystemTotal << 2;
pstartup->cpgMPDB = cbMPDB >> SYS_PAGE_BITS;
if (cbMPDB & (SYS_PAGE_SIZE - 1))
{
pstartup->cpgMPDB++;
cbMPDB = pstartup->cpgMPDB << SYS_PAGE_BITS;
}
/* Initialize the "next page table" pointer. */
pstartup->paFirstPageTable = pstartup->paMPDB + cbMPDB;
g_ptblNext = (PPAGETAB)(pstartup->paFirstPageTable);
/* Map the "prestart" area (everything below load address, plus prestart code & data) as identity. */
VERIFY(map_pages(0, 0, (INT32)(&cpgPrestartTotal), TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01));
/* Map the IO area as identity. */
VERIFY(map_pages(PHYSADDR_IO_BASE, PHYSADDR_IO_BASE, PAGE_COUNT_IO, TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01));
/* Map the library area. */
VERIFY(map_pages((PHYSADDR)(&paLibraryCode), (KERNADDR)(&vmaLibraryCode), (INT32)(&cpgLibraryCode),
TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP10));
/* Map the kernel code area. */
VERIFY(map_pages((PHYSADDR)(&paKernelCode), (KERNADDR)(&vmaKernelCode), (INT32)(&cpgKernelCode),
TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the kernel data/BSS area. */
VERIFY(map_pages((PHYSADDR)(&paKernelData), (KERNADDR)(&vmaKernelData),
(INT32)(&cpgKernelData) + (INT32)(&cpgKernelBss),
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the kernel init code area. */
VERIFY(map_pages((PHYSADDR)(&paInitCode), (KERNADDR)(&vmaInitCode), (INT32)(&cpgInitCode),
TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the kernel init data/BSS area. */
VERIFY(map_pages((PHYSADDR)(&paInitData), (KERNADDR)(&vmaInitData),
(INT32)(&cpgInitData) + (INT32)(&cpgInitBss),
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the TTB itself. */
pstartup->kaTTB = (KERNADDR)(&vmaFirstFree);
VERIFY(map_pages(paTTB, pstartup->kaTTB, SYS_TTB1_SIZE / SYS_PAGE_SIZE,
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the Master Page Database. */
pstartup->kaMPDB = pstartup->kaTTB + SYS_TTB1_SIZE;
VERIFY(map_pages(pstartup->paMPDB, pstartup->kaTTB + SYS_TTB1_SIZE, pstartup->cpgMPDB,
TTBPGTBL_ALWAYS, PGTBLSM_XN | PGTBLSM_ALWAYS | PGTBLSM_B | PGTBLSM_C | PGTBLSM_AP01));
/* Map the IO area into high memory as well. */
VERIFY(map_pages(PHYSADDR_IO_BASE, VMADDR_IO_BASE, PAGE_COUNT_IO, TTBPGTBL_ALWAYS, PGTBLSM_ALWAYS | PGTBLSM_AP01));
#if 0
/* Dump the TTB and page tables to trace output. */
ETrDumpWords((PUINT32)paTTB, (SYS_TTB1_SIZE + (g_cpgForPageTables << SYS_PAGE_BITS)) >> 2);
ETrWriteString8(szPageTable);
ETrWriteWord(g_cpgForPageTables);
ETrWriteString8(szFree);
ETrWriteWord(g_ctblFreeonLastPage);
ETrWriteChar8('\n');
#endif
/* Fill in the rest of the data in the startup info structure. */
pstartup->cpgPageTables = g_cpgForPageTables;
pstartup->ctblFreeOnLastPage = g_ctblFreeonLastPage;
pstartup->paFirstFree = pstartup->paFirstPageTable + (g_cpgForPageTables << SYS_PAGE_BITS);
pstartup->vmaFirstFree = pstartup->kaMPDB + cbMPDB;
return paTTB; /* return this for startup ASM code to use */
}

245
kernel/early_trace.c Normal file
View File

@ -0,0 +1,245 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/llio.h>
#include <comrogue/internals/auxdev.h>
#include <comrogue/internals/gpio.h>
#include <comrogue/internals/16550.h>
#include <comrogue/internals/trace.h>
/* Hex digits. */
static DECLARE_INIT_STRING8_CONST(szHexDigits, "0123456789ABCDEF");
/*
* Initializes the trace functionality (the aux UART).
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Side effects:
* GPIO 14 configured for output from UART1; UART1 initialized to 115200 8N1 and enabled for output.
*/
SEG_INIT_CODE void ETrInit(void)
{
register UINT32 ra;
/* Initialize UART */
llIOWrite(AUX_REG_ENABLE, AUX_ENABLE_MU); /* enable UART1 */
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_CNTL, 0);
llIOWrite(AUX_MU_REG_LCR, U16550_LCR_LENGTH_8|U16550_LCR_PARITY_NONE); /* 8 bits, no parity */
llIOWrite(AUX_MU_REG_MCR, 0);
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_FCR, U16550_FCR_RXCLEAR|U16550_FCR_TXCLEAR|U16550_FCR_LEVEL_14);
llIOWrite(AUX_MU_REG_BAUD, 270); /* 115200 baud */
ra = llIORead(GPFSEL1_REG);
ra &= ~GP_FUNC_MASK(4); /* GPIO 14 - connects to pin 8 on GPIO connector */
ra |= GP_FUNC_BITS(4, GP_PIN_ALT5); /* Alt function 5 - UART1 TxD */
llIOWrite(GPFSEL1_REG, ra);
llIOWrite(GPPUD_REG, 0);
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, GP_BIT(14));
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, 0);
llIOWrite(AUX_MU_REG_CNTL, AUXMU_CNTL_TXENABLE);
}
/*
* Writes a raw character to trace output.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Character written to UART1.
*/
SEG_INIT_CODE static void write_trace(UINT32 c)
{
register UINT32 lsr = llIORead(AUX_MU_REG_LSR);
while (!(lsr & U16550_LSR_TXEMPTY))
lsr = llIORead(AUX_MU_REG_LSR);
llIOWrite(AUX_MU_REG_THR, c);
}
/*
* Writes a character to trace output, translating newlines.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Either 1 or 2 characters written to UART1.
*/
SEG_INIT_CODE void ETrWriteChar8(CHAR c)
{
if (c == '\n')
write_trace('\r');
write_trace((UINT32)c);
}
/*
* Writes a null-terminated string to trace output. Newlines in the string are translated.
*
* Parameters:
* - psz = Pointer to string to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters in string written to UART1.
*/
SEG_INIT_CODE void ETrWriteString8(PCSTR psz)
{
while (*psz)
ETrWriteChar8(*psz++);
}
/*
* Writes the value of a 32-bit word to trace output.
*
* Parameters:
* - uiValue = Value to be written to trace output.
*
* Returns:
* Nothing.
*
* Side effects:
* 8 characters written to UART1.
*/
SEG_INIT_CODE void ETrWriteWord(UINT32 uiValue)
{
register UINT32 uiShift = 32;
do
{
uiShift -= 4;
write_trace(szHexDigits[(uiValue >> uiShift) & 0xF]);
} while (uiShift > 0);
}
/*
* Dumps the values of memory words beginning at a specified address.
*
* Parameters:
* - puiWords = Pointer to words to be dumped.
* - cWords = Number of words to be dumped.
*
* Returns:
* Nothing.
*
* Side effects:
* Many characters written to UART1.
*/
SEG_INIT_CODE void ETrDumpWords(PUINT32 puiWords, UINT32 cWords)
{
static DECLARE_INIT_STRING8_CONST(szSpacer1, ": ");
register UINT32 i;
for (i = 0; i < cWords; i++)
{
if ((i & 0x3) == 0)
{
ETrWriteWord((UINT32)(puiWords + i));
ETrWriteString8(szSpacer1);
}
ETrWriteWord(puiWords[i]);
if ((i & 0x3) == 0x3)
ETrWriteChar8('\n');
else
ETrWriteChar8(' ');
}
if ((cWords & 0x3) != 0)
ETrWriteChar8('\n');
}
/*
* Prints an "assertion failed" message to trace output.
*
* Parameters:
* - pszFile = The file name the assertion was declared in.
* - nLine = The line number the assertion was declared at.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters written to UART1.
*/
SEG_INIT_CODE void ETrAssertFailed(PCSTR pszFile, INT32 nLine)
{
static DECLARE_INIT_STRING8_CONST(szPrefix, "** ASSERTION FAILED: ");
ETrWriteString8(szPrefix);
ETrWriteString8(pszFile);
write_trace(':');
ETrWriteWord((UINT32)nLine);
ETrWriteChar8('\n');
}
/*
* Puts the CPU into a loop where it blinks the green ACTIVITY light forever.
*
* Parameters:
* None.
*
* Returns:
* DOES NOT RETURN!
*
* Side effects:
* GPIO 16 configured for output and turns on and off indefinitely.
*/
SEG_INIT_CODE void ETrInfiniBlink(void)
{
register UINT32 ra;
ra = llIORead(GPFSEL1_REG);
ra &= GP_FUNC_MASK(6); /* GPIO 16 - connects to green ACTIVITY LED */
ra |= GP_FUNC_BITS(6, GP_PIN_OUTPUT); /* output in all circumstances */
llIOWrite(GPFSEL1_REG, ra);
for(;;)
{
llIOWrite(GPSET0_REG, GP_BIT(16));
llIODelay(0x100000);
llIOWrite(GPCLR0_REG, GP_BIT(16));
llIODelay(0x100000);
}
}

81
kernel/intlib.c Normal file
View File

@ -0,0 +1,81 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/types.h>
#include <comrogue/intlib.h>
#include <comrogue/internals/seg.h>
#include "quad.h"
/*---------------------------
* Integer library functions
*---------------------------
*/
/* Flags used internally to IntLDiv. */
#define FLIP_QUOTIENT 0x00000001
#define FLIP_REMAINDER 0x00000002
/*
* Divides two 64-bit integers and returns a quotient and a remainder in a structure.
*
* Parameters:
* - pResult = Pointer to an LDIV structure to contain the quotient and remainder.
* - num = The numerator (dividend) for the division.
* - demom = The demoninator (divisor) for the division.
*
* Returns:
* Standard SUCCEEDED/FAILED HRESULT.
*/
SEG_LIB_CODE HRESULT IntLDiv(PLDIV pResult, INT64 num, INT64 denom)
{
UINT32 mode = 0;
if (denom == 0)
{
pResult->quot = pResult->rem = 0;
return E_INVALIDARG;
}
if (denom < 0)
{
mode ^= FLIP_QUOTIENT;
denom = -denom;
}
if (num < 0)
{
mode ^= (FLIP_QUOTIENT|FLIP_REMAINDER);
num = -num;
}
pResult->quot = __qdivrem(num, denom, (PUINT64)(&(pResult->rem)));
if (mode & FLIP_QUOTIENT)
pResult->quot = -(pResult->quot);
if (mode & FLIP_REMAINDER)
pResult->rem = -(pResult->rem);
return S_OK;
}

94
kernel/kistart.c Normal file
View File

@ -0,0 +1,94 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#define __COMROGUE_INIT__
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/trace.h>
#include <comrogue/internals/startup.h>
#include <comrogue/internals/mmu.h>
#ifdef THIS_FILE
#undef THIS_FILE
DECLARE_THIS_FILE
#endif
/*--------------------------------------------------------------------------------------------------------
* Startup info buffer. Data is copied into here by the assembly code before KiSystemStartup is invoked.
*--------------------------------------------------------------------------------------------------------
*/
SEG_INIT_DATA STARTUP_INFO kiStartupInfo; /* startup info buffer */
SEG_INIT_CODE static void dump_startup_info()
{
TrPrintf8("Mach type %x, revision %x, serial %x\n", kiStartupInfo.uiMachineType, kiStartupInfo.uiRevision,
kiStartupInfo.uiSerialNumber);
TrPrintf8("Memory: %u total pages (%u available), %u TTB gap\n", kiStartupInfo.cpgSystemTotal,
kiStartupInfo.cpgSystemAvail, kiStartupInfo.cpgTTBGap);
TrPrintf8("TTB1 @ PA %08X, VMA %08X\n", kiStartupInfo.paTTB, kiStartupInfo.kaTTB);
TrPrintf8("MPDB @ PA %08X, VMA %08X, %u pages\n", kiStartupInfo.paMPDB, kiStartupInfo.kaMPDB, kiStartupInfo.cpgMPDB);
TrPrintf8("Page tables @ PA %08X, %u pages, %u free on last one\n", kiStartupInfo.paFirstPageTable,
kiStartupInfo.cpgPageTables, kiStartupInfo.ctblFreeOnLastPage);
TrPrintf8("First free PA = %08X, first free VMA = %08X\n", kiStartupInfo.paFirstFree, kiStartupInfo.vmaFirstFree);
TrPrintf8("EMMC clock freq = %u\n", kiStartupInfo.uiEMMCClockFreq);
TrPrintf8("VC memory is at PHYS:%08X, %u bytes, framebuffer %ux%u\n", kiStartupInfo.paVCMem, kiStartupInfo.cbVCMem,
kiStartupInfo.cxFBWidth, kiStartupInfo.cyFBHeight);
TrPrintf8("MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", kiStartupInfo.abMACAddress[0],
kiStartupInfo.abMACAddress[1], kiStartupInfo.abMACAddress[2], kiStartupInfo.abMACAddress[3],
kiStartupInfo.abMACAddress[4], kiStartupInfo.abMACAddress[5]);
}
/*---------------------
* System startup code
*---------------------
*/
static DECLARE_INIT_STRING8_CONST(banner, "--- COMROGUE %d.%02d\n- KiSystemStartup\n");
/*
* Starts the COMROGUE Operating System.
*
* Parameters:
* None.
*
* Returns:
* DOES NOT RETURN!
*
* Side effects:
* Uses the information in kiStartupInfo.
*/
SEG_INIT_CODE void KiSystemStartup(void)
{
TrPrintf8(banner, 0, 0);
dump_startup_info();
TrInfiniBlink();
}

96
kernel/lowlevel.S Normal file
View File

@ -0,0 +1,96 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
.section ".text"
/*------------------------
* Low-level IO functions
*------------------------
*/
/*
* Writes a 32-bit word of data to a memory-mapped IO port.
*
* Parameters:
* - kaPort = Kernel address of the IO port to write to.
* - uiData = Data to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Writing to any given IO port may have arbitrary side effects.
*/
.globl llIOWriteK
llIOWriteK:
str r1,[r0]
bx lr
/*
* Reads a 32-bit word of data from a memory-mapped IO port.
*
* Parameters:
* - kaPort = Kernel address of the IO port we read from.
*
* Returns:
* The word of data read from the IO port.
*
* Side effects:
* Reading from any given IO port may have arbitrary side effects.
*/
.globl llIOReadK
llIOReadK:
ldr r0,[r0]
bx lr
/*
* Delays for a certain number of cycles, to allow an IO operation to work.
*
* Parameters:
* - uiTicks = The number of "ticks" to delay.
*
* Returns:
* Nothing.
*/
.globl llIODelay
llIODelay:
push {lr}
.delaytop:
nop
nop
bl .delayreturn
nop
nop
subs r0, r0, #1
bne .delaytop
pop {lr}
.delayreturn:
bx lr

271
kernel/prestart.S Normal file
View File

@ -0,0 +1,271 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#define __COMROGUE_PRESTART__
#include <comrogue/internals/asm-macros.h>
#include <comrogue/internals/layout.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/sctlr.h>
/*------------------------------------------------------------------------------------------
* The prestart code that gets control when the kernel is first loaded; its objective is to
* set up the MMU and hand over control to the actual start code.
*------------------------------------------------------------------------------------------
*/
.section ".prestartHEAD.text"
.globl COMROGUEPrestart
/* On entry: r0 = 0, r1 = machine type, r2 = atags address */
COMROGUEPrestart:
/* Initialize a temporary stack area. */
mov ip, # PHYSADDR_LOAD
sub sp, ip, #4
/* Go collect the startup info. */
bl KiCollectStartupInfo
mov r11, r0 /* r11 = address of startup info structure */
/* at this point r0-r2 are free for other code to use */
/* Early trace initialize; we reinitialize it later. */
bl ETrInit
ldr r0, =.initMessage
bl ETrWriteString8
/* Copy the early vector table into place, including the vector words that live after the table itself. */
ldr r0, =.earlyVectorTable
ldr r1, =.earlyVectorTableEnd
mov r2, #0
b .vec1
.vec0:
ldm r0!, {r3-r6} /* copy 16 bytes at a time */
stm r2!, {r3-r6}
.vec1:
cmp r0, r1
bne .vec0
/* Initialize early memory management (the TTB1). */
mov r0, r11
bl EMmInit
mov r10, r0 /* r10 = address of TTB */
/* Set up and start the MMU. */
mov ip, #0
mcr p15, 0, ip, c7, c7, 0 /* clear caches */
mcr p15, 0, ip, c8, c7, 0 /* clear TLB */
mov ip, #1
mcr p15, 0, ip, c2, c0, 2 /* set TTBCR */
mvn ip, #0
mcr p15, 0, ip, c3, c0, 0 /* configure domain 0 = client, all others = invalid */
mcr p15, 0, r10, c2, c0, 0 /* set TTB0 */
mcr p15, 0, r10, c2, c0, 1 /* set TTB1 */
mrc p15, 0, ip, c1, c0, 0 /* get control register 1 */
orr ip, ip, # SCTLR_M /* MMU = on */
orr ip, ip, # SCTLR_XP /* subpage AP bits disabled in 2nd-level page tables */
instr_barrier
mcr p15, 0, ip, c1, c0, 0 /* store control register 1 */
mrc p15, 0, ip, c0, c0, 0 /* read ID register */
instr_barrier
#if 0
ldr r0, =.msg1
bl ETrWriteString8
#endif
/* now go to the start area in kernel space */
mov r0, r11
ldr ip, =COMROGUEStart
mov pc, ip
#if 0
.balign 4
.msg1:
.asciz "got here 1\n"
.balign 4
#endif
/*-------------------------------------------------------------
* Early exception-handler code, mainly for debugging purposes
*-------------------------------------------------------------
*/
.earlyReset:
ldr r0, =.resetMessage
b .earlyFUBAR
.earlyUndef:
ldr r0, =.undefMessage
b .earlyFUBAR
.earlySVC:
ldr r0, =.svcMessage
b .earlyFUBAR
.earlyPrefetch:
ldr r0, =.prefetchMessage
b .earlyFUBAR
.earlyData:
ldr r0, =.dataMessage
b .earlyFUBAR
.earlyHyp:
ldr r0, =.hypMessage
b .earlyFUBAR
.earlyIRQ:
ldr r0, =.irqMessage
b .earlyFUBAR
.earlyFIQ:
ldr r0, =.fiqMessage
.earlyFUBAR:
bl ETrWriteString8
.hang:
wfe
b .hang
.earlyVectorTable:
ldr pc, .resetVector
ldr pc, .undefVector
ldr pc, .svcVector
ldr pc, .prefetchVector
ldr pc, .dataVector
ldr pc, .hypVector
ldr pc, .irqVector
ldr pc, .fiqVector
.resetVector:
.word .earlyReset
.undefVector:
.word .earlyUndef
.svcVector:
.word .earlySVC
.prefetchVector:
.word .earlyPrefetch
.dataVector:
.word .earlyData
.hypVector:
.word .earlyHyp
.irqVector:
.word .earlyIRQ
.fiqVector:
.word .earlyFIQ
.earlyVectorTableEnd:
.balign 4
.initMessage:
.asciz "COMROGUEPrestart\n"
.balign 4
.resetMessage:
.asciz "+++ RESET!!!\n"
.balign 4
.undefMessage:
.asciz "+++ UNDEF!!!\n"
.balign 4
.svcMessage:
.asciz "+++ SVC!!!\n"
.balign 4
.prefetchMessage:
.asciz "+++ PREFETCH!!!\n"
.balign 4
.dataMessage:
.asciz "+++ DATA!!!\n"
.balign 4
.hypMessage:
.asciz "+++ HYP!!!\n"
.balign 4
.irqMessage:
.asciz "+++ IRQ!!!\n"
.balign 4
.fiqMessage:
.asciz "+++ FIQ!!!\n"
/*--------------------------------------------------------------------------------------
* Low-level IO functions that are placed here to make them callable from prestart code
*--------------------------------------------------------------------------------------
*/
.section ".prestart.text"
/*
* Writes a 32-bit word of data to a memory-mapped IO port.
*
* Parameters:
* - paPort = Physical address of the IO port to write to.
* - uiData = Data to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Writing to any given IO port may have arbitrary side effects.
*/
.globl llIOWritePA
llIOWritePA:
str r1,[r0]
bx lr
/*
* Reads a 32-bit word of data from a memory-mapped IO port.
*
* Parameters:
* - paPort = Physical address of the IO port we read from.
*
* Returns:
* The word of data read from the IO port.
*
* Side effects:
* Reading from any given IO port may have arbitrary side effects.
*/
.globl llIOReadPA
llIOReadPA:
ldr r0,[r0]
bx lr
/*
* Delays for a certain number of cycles, to allow an IO operation to work.
*
* Parameters:
* - uiTicks = The number of "ticks" to delay.
*
* Returns:
* Nothing.
*/
.globl llIODelayPA
llIODelayPA:
push {lr}
.delaytop:
nop
nop
bl .delayreturn
nop
nop
subs r0, r0, #1
bne .delaytop
pop {lr}
.delayreturn:
bx lr

279
kernel/qdivrem.c Normal file
View File

@ -0,0 +1,279 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that 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.
* 4. 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.
*/
/* Derived from FreeBSD libkern qdivrem.c, munged by Erbo to COMROGUE standards */
#include <comrogue/types.h>
#include <comrogue/internals/seg.h>
#include "quad.h"
/*
* Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
* section 4.3.1, pp. 257--259.
*/
#define B (1 << HALF_BITS) /* digit base */
/* Combine two `digits' to make a single two-digit number. */
#define COMBINE(a, b) (((UINT32)(a) << HALF_BITS) | (b))
/* select a type for digits in base B: use unsigned short if they fit */
typedef UINT16 DIGIT;
/*
* Shift p[0]..p[len] left `sh' bits, ignoring any bits that
* `fall out' the left (there never will be any such anyway).
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
*/
SEG_LIB_CODE static void __shl(register DIGIT *p, register INT32 len, register INT32 sh)
{
register INT32 i;
for (i = 0; i < len; i++)
p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
p[i] = LHALF(p[i] << sh);
}
/*
* __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
*
* We do this in base 2^HALF_BITS, so that all intermediate products
* fit within u_long. As a consequence, the maximum length dividend and
* divisor are 4 `digits' in this base (they are shorter if they have
* leading zeros).
*/
SEG_LIB_CODE UINT64 __qdivrem(UINT64 uq, UINT64 vq, PUINT64 pRem)
{
UU tmp;
DIGIT *u, *v, *q;
register DIGIT v1, v2;
UINT32 qhat, rhat, t;
INT32 m, n, d, j, i;
DIGIT uspace[5], vspace[5], qspace[5];
/*
* Take care of special cases: divide by zero, and u < v.
*/
if (vq == 0)
{ /* divide by zero. */
SEG_LIB_RODATA static volatile const unsigned int zero = 0;
tmp.ul[H] = tmp.ul[L] = 1 / zero;
if (pRem)
*pRem = uq;
return tmp.q;
}
if (uq < vq)
{
if (pRem)
*pRem = uq;
return 0;
}
u = uspace;
v = vspace;
q = qspace;
/*
* Break dividend and divisor into digits in base B, then
* count leading zeros to determine m and n. When done, we
* will have:
* u = (u[1]u[2]...u[m+n]) sub B
* v = (v[1]v[2]...v[n]) sub B
* v[1] != 0
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
* m >= 0 (otherwise u < v, which we already checked)
* m + n = 4
* and thus
* m = 4 - n <= 2
*/
tmp.uq = uq;
u[0] = 0;
u[1] = HHALF(tmp.ul[H]);
u[2] = LHALF(tmp.ul[H]);
u[3] = HHALF(tmp.ul[L]);
u[4] = LHALF(tmp.ul[L]);
tmp.uq = vq;
v[1] = HHALF(tmp.ul[H]);
v[2] = LHALF(tmp.ul[H]);
v[3] = HHALF(tmp.ul[L]);
v[4] = LHALF(tmp.ul[L]);
for (n = 4; v[1] == 0; v++)
{
if (--n == 1)
{
UINT32 rbj; /* r*B+u[j] (not root boy jim) */
DIGIT q1, q2, q3, q4;
/*
* Change of plan, per exercise 16.
* r = 0;
* for j = 1..4:
* q[j] = floor((r*B + u[j]) / v),
* r = (r*B + u[j]) % v;
* We unroll this completely here.
*/
t = v[2]; /* nonzero, by definition */
q1 = u[1] / t;
rbj = COMBINE(u[1] % t, u[2]);
q2 = rbj / t;
rbj = COMBINE(rbj % t, u[3]);
q3 = rbj / t;
rbj = COMBINE(rbj % t, u[4]);
q4 = rbj / t;
if (pRem)
*pRem = rbj % t;
tmp.ul[H] = COMBINE(q1, q2);
tmp.ul[L] = COMBINE(q3, q4);
return tmp.q;
}
}
/*
* By adjusting q once we determine m, we can guarantee that
* there is a complete four-digit quotient at &qspace[1] when
* we finally stop.
*/
for (m = 4 - n; u[1] == 0; u++)
m--;
for (i = 4 - m; --i >= 0;)
q[i] = 0;
q += 4 - m;
/*
* Here we run Program D, translated from MIX to C and acquiring
* a few minor changes.
*
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
*/
d = 0;
for (t = v[1]; t < B / 2; t <<= 1)
d++;
if (d > 0)
{
__shl(u, m + n, d); /* u <<= d */
__shl(v + 1, n - 1, d); /* v <<= d */
}
/*
* D2: j = 0.
*/
j = 0;
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
v2 = v[2]; /* for D3 */
do
{
register DIGIT uj0, uj1, uj2;
/*
* D3: Calculate qhat (\^q, in TeX notation).
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
* let rhat = (u[j]*B + u[j+1]) mod v[1].
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
* decrement qhat and increase rhat correspondingly.
* Note that if rhat >= B, v[2]*qhat < rhat*B.
*/
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
uj1 = u[j + 1]; /* for D3 only */
uj2 = u[j + 2]; /* for D3 only */
if (uj0 == v1)
{
qhat = B;
rhat = uj1;
goto qhat_too_big;
}
else
{
UINT32 nn = COMBINE(uj0, uj1);
qhat = nn / v1;
rhat = nn % v1;
}
while (v2 * qhat > COMBINE(rhat, uj2))
{
qhat_too_big:
qhat--;
if ((rhat += v1) >= B)
break;
}
/*
* D4: Multiply and subtract.
* The variable `t' holds any borrows across the loop.
* We split this up so that we do not require v[0] = 0,
* and to eliminate a final special case.
*/
for (t = 0, i = n; i > 0; i--)
{
t = u[i + j] - v[i] * qhat - t;
u[i + j] = LHALF(t);
t = (B - HHALF(t)) & (B - 1);
}
t = u[j] - t;
u[j] = LHALF(t);
/*
* D5: test remainder.
* There is a borrow if and only if HHALF(t) is nonzero;
* in that (rare) case, qhat was too large (by exactly 1).
* Fix it by adding v[1..n] to u[j..j+n].
*/
if (HHALF(t))
{
qhat--;
for (t = 0, i = n; i > 0; i--)
{ /* D6: add back. */
t += u[i + j] + v[i];
u[i + j] = LHALF(t);
t = HHALF(t);
}
u[j] = LHALF(u[j] + t);
}
q[j] = qhat;
} while (++j <= m); /* D7: loop on j. */
/*
* If caller wants the remainder, we have to calculate it as
* u[m..m+n] >> d (this is at most n digits and thus fits in
* u[m+1..m+n], but we may need more source digits).
*/
if (pRem)
{
if (d)
{
for (i = m + n; i > m; --i)
u[i] = (u[i] >> d) | LHALF(u[i - 1] << (HALF_BITS - d));
u[i] = 0;
}
tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
*pRem = tmp.q;
}
tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
return tmp.q;
}

71
kernel/quad.h Normal file
View File

@ -0,0 +1,71 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that 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.
* 4. 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.
*
* @(#)quad.h 8.1 (Berkeley) 6/4/93
* $FreeBSD$
*/
/* Derived from FreeBDS libkern quad.h, munged by Erbo to COMROGUE standards */
#ifndef QUAD_H_INCLUDED
#define QUAD_H_INCLUDED
#include <comrogue/types.h>
typedef union tagUU {
INT64 q; /* signed quad */
UINT64 uq; /* unsigned quad */
INT32 sl[2]; /* two signed longs */
UINT32 ul[2]; /* two unsigned longs */
} UU;
/* Low word/high word definitions. */
#define L 0
#define H 1
/* Number of bits in a halfword. */
#define HALF_BITS (INT32_BITS / 2)
/*
* Extract high and low shortwords from longword, and move low shortword of
* longword to upper half of long, i.e., produce the upper longword of
* ((quad_t)(x) << (number_of_bits_in_long/2)). (`x' must actually be u_long.)
*
* These are used in the multiply code, to split a longword into upper
* and lower halves, and to reassemble a product as a quad_t, shifted left
* (sizeof(long)*CHAR_BIT/2).
*/
#define HHALF(x) ((x) >> HALF_BITS)
#define LHALF(x) ((x) & ((1 << HALF_BITS) - 1))
#define LHUP(x) ((x) << HALF_BITS)
extern UINT64 __qdivrem(UINT64 u, UINT64 v, PUINT64 pRem);
#endif /* QUAD_H_INCLUDED */

117
kernel/start.S Normal file
View File

@ -0,0 +1,117 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/internals/layout.h>
#include <comrogue/internals/sctlr.h>
.section ".initHEAD.text"
.globl COMROGUEStart
/* entry: r0 = physical (low-memory) address of STARTUP_INFO1 structure */
COMROGUEStart:
/* initialize the stack pointer */
ldr sp, =.initstack
/* clear init bss */
ldr r4, =vmaInitBss
ldr r5, =vmaFirstFree
mov r6, #0
mov r7, #0
mov r8, #0
mov r9, #0
bl .erase
/* clear resident bss */
ldr r4, =vmaKernelBss
ldr r5, =vmaInitCode
bl .erase
/* initialize trace */
push {r0}
bl TrInit
#if 0
ldr r0, =.msg0
bl TrWriteString8
#endif
pop {r0}
/* copy startup info to our local buffer */
mov r1, r0
ldr r0, =kiStartupInfo
mov r11, r0 /* save for later */
ldr r2, [r1] /* get number of bytes to copy */
ldr ip, =StrCopyMem /* this is needed to branch to a library function */
ldr lr, =.postCopy
mov pc, ip
.postCopy:
#if 0
ldr r0, =.msg1
bl TrWriteString8
#endif
mcr p15, 0, r6, c7, c7, 0 /* clear caches */
mcr p15, 0, r6, c8, c7, 0 /* clear TLB */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, # SCTLR_I /* activate instruction cache */
orr r0, r0, # SCTLR_C /* activate data cache */
mcr p15, 0, r0, c1, c0, 0
/* transfer to C code to continue initialization */
ldr ip, =KiSystemStartup
ldr lr, =.hang
mov pc, ip /* transfer to C code */
.hang:
wfe /* if KiSystemStartup returns, just hang */
b .hang
/* Simple erase routine. Start and end addresses in r4 and r5. r6-r9 assumed to be 0. */
/* Do not touch r0-r2. */
.erase:
cmp r4, r5 /* are we done? */
movhs pc, lr /* yes, return */
stm r4!, {r6-r9} /* stomp 16 bytes */
b .erase
#if 0
.balign 4
.msg0:
.asciz "got here 2\n"
.balign 4
.msg1:
.asciz "got here 3\n"
#endif
.section ".init.bss"
.balign 4
.space 4096
.initstack:

423
kernel/str.c Normal file
View File

@ -0,0 +1,423 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/intlib.h>
#include <comrogue/str.h>
#include <comrogue/internals/seg.h>
/*-------------------------
* Basic string operations
*-------------------------
*/
/*
* Returns whether or not the character is a digit (0-9).
*
* Parameters:
* - ch = Character to be tested.
*
* Returns:
* TRUE if the character is a digit, FALSE otherwise.
*/
SEG_LIB_CODE BOOL StrIsDigit8(CHAR ch)
{
/* TODO: replace with something nicer later */
return MAKEBOOL((ch >= '0') && (ch <= '9'));
}
/*
* Returns the length of a null-terminated string.
*
* Parameters:
* - psz = The string to get the length of.
*
* Returns:
* The length of the string in characters.
*/
SEG_LIB_CODE INT32 StrLength8(PCSTR psz)
{
register PCSTR p = psz;
while (*p)
p++;
return (INT32)(p - psz);
}
/*
* Locates a character within a null-terminated string.
*
* Parameters:
* - psz = String to search through for character.
* - ch = Character to look for.
*
* Returns:
* NULL if character was not found, otherwise pointer to character within string.
*/
SEG_LIB_CODE PCHAR StrChar8(PCSTR psz, INT32 ch)
{
const CHAR mych = ch;
for (; *psz; psz++)
if (*psz == mych)
return (PCHAR)psz;
return NULL;
}
/*-------------------------------
* Numeric-to-string conversions
*-------------------------------
*/
/*
* Formats an unsigned numeric value into a buffer. This function formats the value into the END of the
* buffer and returns a pointer to the first character of the number. Note that the string-converted number
* is NOT null-terminated!
*
* Parameters:
* - value = The value to be converted.
* - pchBuf = Pointer to the buffer in which to store the converted value.
* - nBytes = Number of characters in the buffer.
* - nBase = The numeric base to use to output the number. Valid values are in the interval [2,36].
* - fUppercase = TRUE to use upper-case letters as digits in output, FALSE to use lower-case letters.
*
* Returns:
* A pointer to the first digit of the converted value, which will be somewhere in the interval
* [pchBuf, pchBuf + nBytes).
*/
SEG_LIB_CODE static PCHAR convert_number_engine8(UINT64 value, PCHAR pchBuf, INT32 nBytes, INT32 nBase,
BOOL fUppercase)
{
static DECLARE_LIB_STRING8_CONST(szDigitsUppercase, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
static DECLARE_LIB_STRING8_CONST(szDigitsLowercase, "0123456789abcdefghijklmnopqrstuvwxyz");
PCSTR pszDigits = (fUppercase ? szDigitsUppercase : szDigitsLowercase); /* digit set to use */
PCHAR p = pchBuf + nBytes; /* output pointer */
INT64 accumulator; /* accumulator of quotients */
LDIV ldiv; /* buffer for division */
/* do initial division to get rid of high-order bit & handle 0 */
*--p = pszDigits[value % nBase];
accumulator = (INT64)(value / nBase);
while ((p > pchBuf) && (accumulator > 0))
{ /* output digits */
IntLDiv(&ldiv, accumulator, nBase);
*--p = pszDigits[ldiv.rem];
accumulator = ldiv.quot;
}
return p;
}
/*-----------------------------------------
* StrFormatV8 and its support definitions
*-----------------------------------------
*/
/* Flag values for conversion characters */
#define FLAG_LEFTJUST 0x01 /* left-justify output field */
#define FLAG_PLUSSIGN 0x02 /* use a '+' for the sign if >= 0 */
#define FLAG_SPACESIGN 0x04 /* use a space for the sign if >= 0 */
#define FLAG_ALTMODE 0x08 /* alternate conversion mode */
#define FLAG_ZEROPAD 0x10 /* zero-pad to width */
/* Macro that calls the output function and either updates total output or exits */
#define do_output(pBuf, nChr) \
do { if ((nChr) > 0) { if (SUCCEEDED((*pfnFormat)(&pArg, (pBuf), (nChr)))) nTotalOutput += (nChr); \
else { errorFlag = SEVERITY_ERROR; goto error; } } } while (0)
/* Strings used for padding */
static DECLARE_LIB_STRING8_CONST(szPadSpace, " ");
static DECLARE_LIB_STRING8_CONST(szPadZero, "0000000000000000000000000000000000000000000000000000000000");
#define PAD_SIZE (sizeof(szPadSpace) - 1) /* number of characters available in pad string */
/* Macro that outputs characters for padding */
#define do_pad_output(szPad, nChr) \
do { int n, nt = (nChr); while (nt > 0) { n = intMin(nt, PAD_SIZE); do_output(szPad, n); nt -= n; } } while (0)
#define MAX_VAL 509 /* maximum field value for conversion */
#define BUFSIZE 64 /* buffer size on stack for conversion */
#define NUM_CONVERT_BYTES 32 /* maximum number of bytes for converting a numeric value */
/*
* Format a series of arguments like "printf," calling a function to perform the actual character output.
*
* Parameters:
* - pfnFormat = Pointer to the format function
* - pArg = Pointer argument passed to the format function, which may modify it
* - pszFormat = Format string, like a printf format string.
* - pargs = Pointer to varargs-style function arguments.
*
* Returns:
* A HRESULT as follows: Severity indicates whether the output function failed or succeeded, facility is always
* FACILITY_STRFORMAT, code indicates the number of characters output.
*
* Notes:
* Floating-point conversion formats are not supported at this time.
*/
SEG_LIB_CODE HRESULT StrFormatV8(PFNFORMAT8 pfnFormat, PVOID pArg, PCSTR pszFormat, va_list pargs)
{
static DECLARE_LIB_STRING8_CONST(szFlagChars, "0+- #"); /* flag characters and values */
static const UINT32 SEG_LIB_RODATA auiFlagValues[] =
{ FLAG_ZEROPAD, FLAG_LEFTJUST, FLAG_PLUSSIGN, FLAG_SPACESIGN, FLAG_ALTMODE, 0 };
static DECLARE_LIB_STRING8_CONST(szConversionChars, "hl"); /* conversion characters */
PCSTR p; /* pointer used to walk the format string */
PCHAR pFlag; /* pointer to flag character/temp buffer pointer */
PCHAR pchOutput; /* pointer to characters actually output */
INT32 nchOutput; /* number of characters output */
PCHAR pchPrefix; /* pointer to prefix characters */
INT32 nchPrefix; /* number of prefix characters */
INT32 nchZeroPrefix; /* number of zeroes to write as a prefix */
INT32 nTotalOutput = 0; /* total number of characters output */
UINT32 errorFlag = SEVERITY_SUCCESS; /* error flag to return */
UINT32 flags; /* conversion flags seen */
INT32 ncWidth; /* width for field */
INT32 ncPrecision; /* precision for field */
INT32 nBase; /* numeric base for field */
INT64 input; /* input integer value */
CHAR chConvert; /* conversion character for field */
CHAR achBuffer[BUFSIZE]; /* buffer into which output is formatted */
while (*pszFormat)
{
/* locate all plain characters up to next % or end of string and output them */
p = pszFormat;
while (*p && (*p != '%'))
p++;
do_output(pszFormat, p - pszFormat);
if (*p == '%')
{
flags = 0; /* convert flags first */
for (p++; (pFlag = StrChar8(szFlagChars, *p)) != NULL; p++)
flags |= auiFlagValues[pFlag - szFlagChars];
ncWidth = 0; /* now convert width */
if (*p == '*')
{
ncWidth = va_arg(pargs, INT32); /* specified by arg */
p++;
if (ncWidth < 0)
{
flags |= FLAG_LEFTJUST; /* negative width is taken as use of - flag */
ncWidth = -ncWidth;
}
}
else
{
while (StrIsDigit8(*p))
ncWidth = ncWidth * 10 + (*p++ - '0');
}
if (ncWidth > MAX_VAL)
ncWidth = MAX_VAL;
ncPrecision = -1; /* now convert precision */
if (*p == '.')
{
p++;
if (*p == '*')
{
ncPrecision = va_arg(pargs, INT32); /* specified by arg */
p++;
/* N.B. ncPrecision < 0 = "omitted precision" */
}
else
{
ncPrecision = 0;
while (StrIsDigit8(*p))
ncPrecision = ncPrecision * 10 + (*p++ - '0');
}
if (ncPrecision > MAX_VAL)
ncPrecision = MAX_VAL;
}
chConvert = StrChar8(szConversionChars, *p) ? *p++ : '\0'; /* get conversion character */
/* based on field character, convert the field */
pchOutput = achBuffer;
nchOutput = 0;
pchPrefix = NULL;
nchPrefix = 0;
nchZeroPrefix = 0;
switch (*p)
{
case 'c': /* output a character */
achBuffer[nchOutput++] = (CHAR)va_arg(pargs, INT32);
break;
case 'd':
case 'i': /* output a decimal number */
if (ncPrecision < 0)
ncPrecision = 1; /* default precision is 1 */
if (chConvert == 'h')
input = va_arg(pargs, INT32);
else if (chConvert == '\0')
input = va_arg(pargs, INT32);
else
input = va_arg(pargs, INT64);
if ((input == 0) && (ncPrecision == 0))
break; /* no output */
if (input < 0)
{
achBuffer[nchPrefix++] = '-'; /* minus sign */
input = -input;
}
else
{
/* plus or space for sign if flags dictate */
if (flags & FLAG_PLUSSIGN)
achBuffer[nchPrefix++] = '+';
else if (flags & FLAG_SPACESIGN)
achBuffer[nchPrefix++] = ' ';
}
if (nchPrefix > 0)
{
pchPrefix = achBuffer; /* adjust output pointer and set prefix */
pchOutput = achBuffer + nchPrefix;
}
/* clamp input value and run it through number conversion engine */
if (chConvert == 'h')
input &= UINT16_MAX;
else if (chConvert == '\0')
input &= UINT32_MAX;
pFlag = pchOutput;
pchOutput = convert_number_engine8((UINT64)input, pFlag, NUM_CONVERT_BYTES, 10, FALSE);
nchOutput = (pFlag + NUM_CONVERT_BYTES) - pchOutput;
/* calculate zero prefix based on precision */
if ((flags & (FLAG_ZEROPAD|FLAG_LEFTJUST)) == FLAG_ZEROPAD)
nchZeroPrefix = intMax(0, ncWidth - (nchPrefix + nchOutput));
else if (ncPrecision > 0)
nchZeroPrefix = intMax(0, ncPrecision - nchOutput);
break;
case 'o':
case 'u':
case 'x':
case 'X': /* output an unsigned number */
if (ncPrecision < 0)
ncPrecision = 1; /* defualt precision is 1 */
if (chConvert == 'h')
input = va_arg(pargs, UINT32);
else if (chConvert == '\0')
input = va_arg(pargs, UINT32);
else
input = (INT64)va_arg(pargs, UINT64);
if ((input == 0) && (ncPrecision == 0))
break; /* no output */
/* select numeric base of output */
if (*p == 'o')
nBase = 8;
else if (*p == 'u')
nBase = 10;
else
nBase = 16;
if (flags & FLAG_ALTMODE)
{
if (*p == 'o')
{ /* forced octal notation */
achBuffer[nchPrefix++] = '0';
ncPrecision--;
}
else if (*p != 'u')
{ /* forced hexadecimal notation */
achBuffer[nchPrefix++] = '0';
achBuffer[nchPrefix++] = *p;
}
}
if (nchPrefix > 0)
{
pchPrefix = achBuffer; /* adjust output pointer and set prefix */
pchOutput = achBuffer + nchPrefix;
}
/* clamp input value and run it through number conversion engine */
if (chConvert == 'h')
input &= UINT16_MAX;
else if (chConvert == '\0')
input &= UINT32_MAX;
pFlag = pchOutput;
pchOutput = convert_number_engine8((UINT64)input, pFlag, NUM_CONVERT_BYTES, nBase, MAKEBOOL(*p == 'X'));
nchOutput = (pFlag + NUM_CONVERT_BYTES) - pchOutput;
/* calculate zero prefix based on precision */
if ((flags & (FLAG_ZEROPAD|FLAG_LEFTJUST)) == FLAG_ZEROPAD)
nchZeroPrefix = intMax(0, ncWidth - (nchPrefix + nchOutput));
else if (ncPrecision > 0)
nchZeroPrefix = intMax(0, ncPrecision - nchOutput);
break;
case 'p': /* output a pointer value - treated as unsigned hex with precision of 8 */
input = (INT_PTR)va_arg(pargs, PVOID);
input &= UINT_PTR_MAX;
pFlag = pchOutput;
pchOutput = convert_number_engine8((UINT64)input, pFlag, NUM_CONVERT_BYTES, 16, FALSE);
nchOutput = (pFlag + NUM_CONVERT_BYTES) - pchOutput;
nchZeroPrefix = intMax(0, (sizeof(UINT_PTR) / sizeof(CHAR) * 2) - nchOutput);
break;
case 's': /* output a string */
pchOutput = (PCHAR)va_arg(pargs, PCSTR);
nchOutput = StrLength8(pchOutput);
if ((ncPrecision >= 0) && (ncPrecision < nchOutput))
nchOutput = ncPrecision;
break;
case 'n': /* output nothing, just store number of characters output so far */
*(va_arg(pargs, PINT32)) = nTotalOutput;
goto no_output;
case '%': /* output a single % sign */
default: /* unrecognized format character, output it and continue */
achBuffer[nchOutput++] = *p;
break;
}
ncWidth -= (nchPrefix + nchZeroPrefix + nchOutput);
if (!(flags & FLAG_LEFTJUST))
do_pad_output(szPadSpace, ncWidth);
do_output(pchPrefix, nchPrefix);
do_pad_output(szPadZero, nchZeroPrefix);
do_output(pchOutput, nchOutput);
if (flags & FLAG_LEFTJUST)
do_pad_output(szPadSpace, ncWidth);
no_output:
p++;
}
pszFormat = p;
}
error:
return MAKE_SCODE(errorFlag, FACILITY_STRFORMAT, nTotalOutput);
}

273
kernel/strcopymem.S Normal file
View File

@ -0,0 +1,273 @@
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 FreeBSD memcpy_arm.S, munged by Erbo to COMROGUE standards */
.section ".lib.text"
/*
* This is one fun bit of code ...
* Some easy listening music is suggested while trying to understand this
* code e.g. Iron Maiden
*
* For anyone attempting to understand it :
*
* The core code is implemented here with simple stubs for memcpy().
*
* All local labels are prefixed with Lmemcpy_
* Following the prefix a label starting f is used in the forward copy code
* while a label using b is used in the backwards copy code
* The source and destination addresses determine whether a forward or
* backward copy is performed.
* Separate bits of code are used to deal with the following situations
* for both the forward and backwards copy.
* unaligned source address
* unaligned destination address
* Separate copy routines are used to produce an optimised result for each
* of these cases.
* The copy code will use LDM/STM instructions to copy up to 32 bytes at
* a time where possible.
*
* Note: r12 (aka ip) can be trashed during the function along with
* r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
* Additional registers are preserved prior to use i.e. r4, r5 & lr
*
* Apologies for the state of the comments ;-)
*/
/* Func: PVOID StrCopyMem(PVOID pDest, PCVOID pSrc, INT32 nBytes); */
/*
* Copies memory data from one block of memory to another. Assumes the memory blocks do NOT overlap.
*
* Parameters:
* - pDest = Destination for the copy operation.
* - pSrc = Source for the copy operation.
* - nBytes = Number of bytes to be copied.
*
* Returns:
* pDest.
*/
.globl StrCopyMem
StrCopyMem:
/* save leaf functions having to store this away */
stmdb sp!, {r0, lr} /* memcpy() returns dest addr */
subs r2, r2, #4
blt .Lmemcpy_l4 /* less than 4 bytes */
ands r12, r0, #3
bne .Lmemcpy_destul /* oh unaligned destination addr */
ands r12, r1, #3
bne .Lmemcpy_srcul /* oh unaligned source addr */
.Lmemcpy_t8:
/* We have aligned source and destination */
subs r2, r2, #8
blt .Lmemcpy_l12 /* less than 12 bytes (4 from above) */
subs r2, r2, #0x14
blt .Lmemcpy_l32 /* less than 32 bytes (12 from above) */
stmdb sp!, {r4} /* borrow r4 */
/* blat 32 bytes at a time */
/* XXX for really big copies perhaps we should use more registers */
.Lmemcpy_loop32:
ldmia r1!, {r3, r4, r12, lr}
stmia r0!, {r3, r4, r12, lr}
ldmia r1!, {r3, r4, r12, lr}
stmia r0!, {r3, r4, r12, lr}
subs r2, r2, #0x20
bge .Lmemcpy_loop32
cmn r2, #0x10
ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
stmgeia r0!, {r3, r4, r12, lr}
subge r2, r2, #0x10
ldmia sp!, {r4} /* return r4 */
.Lmemcpy_l32:
adds r2, r2, #0x14
/* blat 12 bytes at a time */
.Lmemcpy_loop12:
ldmgeia r1!, {r3, r12, lr}
stmgeia r0!, {r3, r12, lr}
subges r2, r2, #0x0c
bge .Lmemcpy_loop12
.Lmemcpy_l12:
adds r2, r2, #8
blt .Lmemcpy_l4
subs r2, r2, #4
ldrlt r3, [r1], #4
strlt r3, [r0], #4
ldmgeia r1!, {r3, r12}
stmgeia r0!, {r3, r12}
subge r2, r2, #4
.Lmemcpy_l4:
/* less than 4 bytes to go */
adds r2, r2, #4
ldmeqia sp!, {r0, pc} /* done */
/* copy the crud byte at a time */
cmp r2, #2
ldrb r3, [r1], #1
strb r3, [r0], #1
ldrgeb r3, [r1], #1
strgeb r3, [r0], #1
ldrgtb r3, [r1], #1
strgtb r3, [r0], #1
ldmia sp!, {r0, pc}
/* erg - unaligned destination */
.Lmemcpy_destul:
rsb r12, r12, #4
cmp r12, #2
/* align destination with byte copies */
ldrb r3, [r1], #1
strb r3, [r0], #1
ldrgeb r3, [r1], #1
strgeb r3, [r0], #1
ldrgtb r3, [r1], #1
strgtb r3, [r0], #1
subs r2, r2, r12
blt .Lmemcpy_l4 /* less the 4 bytes */
ands r12, r1, #3
beq .Lmemcpy_t8 /* we have an aligned source */
/* erg - unaligned source */
/* This is where it gets nasty ... */
.Lmemcpy_srcul:
bic r1, r1, #3
ldr lr, [r1], #4
cmp r12, #2
bgt .Lmemcpy_srcul3
beq .Lmemcpy_srcul2
cmp r2, #0x0c
blt .Lmemcpy_srcul1loop4
sub r2, r2, #0x0c
stmdb sp!, {r4, r5}
.Lmemcpy_srcul1loop16:
mov r3, lr, lsr #8
ldmia r1!, {r4, r5, r12, lr}
orr r3, r3, r4, lsl #24
mov r4, r4, lsr #8
orr r4, r4, r5, lsl #24
mov r5, r5, lsr #8
orr r5, r5, r12, lsl #24
mov r12, r12, lsr #8
orr r12, r12, lr, lsl #24
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul1loop16
ldmia sp!, {r4, r5}
adds r2, r2, #0x0c
blt .Lmemcpy_srcul1l4
.Lmemcpy_srcul1loop4:
mov r12, lr, lsr #8
ldr lr, [r1], #4
orr r12, r12, lr, lsl #24
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul1loop4
.Lmemcpy_srcul1l4:
sub r1, r1, #3
b .Lmemcpy_l4
.Lmemcpy_srcul2:
cmp r2, #0x0c
blt .Lmemcpy_srcul2loop4
sub r2, r2, #0x0c
stmdb sp!, {r4, r5}
.Lmemcpy_srcul2loop16:
mov r3, lr, lsr #16
ldmia r1!, {r4, r5, r12, lr}
orr r3, r3, r4, lsl #16
mov r4, r4, lsr #16
orr r4, r4, r5, lsl #16
mov r5, r5, lsr #16
orr r5, r5, r12, lsl #16
mov r12, r12, lsr #16
orr r12, r12, lr, lsl #16
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul2loop16
ldmia sp!, {r4, r5}
adds r2, r2, #0x0c
blt .Lmemcpy_srcul2l4
.Lmemcpy_srcul2loop4:
mov r12, lr, lsr #16
ldr lr, [r1], #4
orr r12, r12, lr, lsl #16
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul2loop4
.Lmemcpy_srcul2l4:
sub r1, r1, #2
b .Lmemcpy_l4
.Lmemcpy_srcul3:
cmp r2, #0x0c
blt .Lmemcpy_srcul3loop4
sub r2, r2, #0x0c
stmdb sp!, {r4, r5}
.Lmemcpy_srcul3loop16:
mov r3, lr, lsr #24
ldmia r1!, {r4, r5, r12, lr}
orr r3, r3, r4, lsl #8
mov r4, r4, lsr #24
orr r4, r4, r5, lsl #8
mov r5, r5, lsr #24
orr r5, r5, r12, lsl #8
mov r12, r12, lsr #24
orr r12, r12, lr, lsl #8
stmia r0!, {r3-r5, r12}
subs r2, r2, #0x10
bge .Lmemcpy_srcul3loop16
ldmia sp!, {r4, r5}
adds r2, r2, #0x0c
blt .Lmemcpy_srcul3l4
.Lmemcpy_srcul3loop4:
mov r12, lr, lsr #24
ldr lr, [r1], #4
orr r12, r12, lr, lsl #8
str r12, [r0], #4
subs r2, r2, #4
bge .Lmemcpy_srcul3loop4
.Lmemcpy_srcul3l4:
sub r1, r1, #1
b .Lmemcpy_l4

290
kernel/trace.c Normal file
View File

@ -0,0 +1,290 @@
/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* 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.
*
* THIS SOFTWARE IS 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 HOLDER 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.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
#include <stdarg.h>
#include <comrogue/types.h>
#include <comrogue/str.h>
#include <comrogue/internals/seg.h>
#include <comrogue/internals/llio.h>
#include <comrogue/internals/auxdev.h>
#include <comrogue/internals/gpio.h>
#include <comrogue/internals/16550.h>
/* Hex digits. */
static DECLARE_STRING8_CONST(szHexDigits, "0123456789ABCDEF");
/*
* Initializes the trace functionality (the aux UART).
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Side effects:
* GPIO 14 configured for output from UART1; UART1 initialized to 115200 8N1 and enabled for output.
*/
void TrInit(void)
{
register UINT32 ra;
/* Initialize UART */
llIOWrite(AUX_REG_ENABLE, AUX_ENABLE_MU); /* enable UART1 */
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_CNTL, 0);
llIOWrite(AUX_MU_REG_LCR, U16550_LCR_LENGTH_8|U16550_LCR_PARITY_NONE); /* 8 bits, no parity */
llIOWrite(AUX_MU_REG_MCR, 0);
llIOWrite(AUX_MU_REG_IER, 0);
llIOWrite(AUX_MU_REG_FCR, U16550_FCR_RXCLEAR|U16550_FCR_TXCLEAR|U16550_FCR_LEVEL_14);
llIOWrite(AUX_MU_REG_BAUD, 270); /* 115200 baud */
ra = llIORead(GPFSEL1_REG);
ra &= ~GP_FUNC_MASK(4); /* GPIO 14 - connects to pin 8 on GPIO connector */
ra |= GP_FUNC_BITS(4, GP_PIN_ALT5); /* Alt function 5 - UART1 TxD */
llIOWrite(GPFSEL1_REG, ra);
llIOWrite(GPPUD_REG, 0);
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, GP_BIT(14));
llIODelay(150);
llIOWrite(GPPUDCLK0_REG, 0);
llIOWrite(AUX_MU_REG_CNTL, AUXMU_CNTL_TXENABLE);
}
/*
* Makes sure all trace output has been flushed out the UART.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Side effects:
* UART1 transmitter is empty upon return from this function.
*/
static void flush_trace(void)
{
register UINT32 lsr = llIORead(AUX_MU_REG_LSR);
while (!(lsr & U16550_LSR_TXEMPTY))
lsr = llIORead(AUX_MU_REG_LSR);
}
/*
* Writes a raw character to trace output.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Character written to UART1.
*/
static void write_trace(UINT32 c)
{
flush_trace();
llIOWrite(AUX_MU_REG_THR, c);
}
/*
* Writes a character to trace output, translating newlines.
*
* Parameters:
* - c = The character to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Either 1 or 2 characters written to UART1.
*/
void TrWriteChar8(CHAR c)
{
if (c == '\n')
write_trace('\r');
write_trace((UINT32)c);
}
/*
* Writes a null-terminated string to trace output. Newlines in the string are translated.
*
* Parameters:
* - psz = Pointer to string to be written.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters in string written to UART1.
*/
void TrWriteString8(PCSTR psz)
{
while (*psz)
TrWriteChar8(*psz++);
}
/*
* Writes the value of a 32-bit word to trace output.
*
* Parameters:
* - uiValue = Value to be written to trace output.
*
* Returns:
* Nothing.
*
* Side effects:
* 8 characters written to UART1.
*/
void TrWriteWord(UINT32 uiValue)
{
register UINT32 uiShift = 32;
do
{
uiShift -= 4;
write_trace(szHexDigits[(uiValue >> uiShift) & 0xF]);
} while (uiShift > 0);
}
/*
* Used by the "trace printf" functions to actually output character data.
*
* Parameters:
* - pDummy = Always points to a NULL value; not used.
* - pchData = Pointer to the data to be written.
* - cchData = The number of characters to be written.
*
* Returns:
* S_OK in all circumstances.
*
* Side effects:
* cchData characters written to UART1.
*/
static HRESULT write_trace_buf8(PPVOID pDummy, PCCHAR pchData, UINT32 cchData)
{
register UINT32 i;
for (i=0; i<cchData; i++)
TrWriteChar8(pchData[i]);
return S_OK;
}
/*
* Formats output to the trace output.
*
* Parameters:
* - pszFormat = Format string for the output, like a printf format string.
* - pargs = Pointer to varargs-style function arguments.
*
* Returns:
* A HRESULT as follows: Severity indicates whether the output function failed or succeeded, facility is always
* FACILITY_STRFORMAT, code indicates the number of characters output.
*
* Side effects:
* Characters written to UART1, the count of which is given by the output code.
*/
HRESULT TrVPrintf8(PCSTR pszFormat, va_list pargs)
{
return StrFormatV8(write_trace_buf8, NULL, pszFormat, pargs);
}
/*
* Formats output to the trace output.
*
* Parameters:
* - pszFormat = Format string for the output, like a printf format string.
* - <args> = Arguments to be substitute dinto the format string.
*
* Returns:
* A HRESULT as follows: Severity indicates whether the output function failed or succeeded, facility is always
* FACILITY_STRFORMAT, code indicates the number of characters output.
*
* Side effects:
* Characters written to UART1, the count of which is given by the output code.
*/
HRESULT TrPrintf8(PCSTR pszFormat, ...)
{
HRESULT hr;
va_list argp;
va_start(argp, pszFormat);
hr = StrFormatV8(write_trace_buf8, NULL, pszFormat, argp);
va_end(argp);
return hr;
}
/*
* Prints an "assertion failed" message to trace output.
*
* Parameters:
* - pszFile = The file name the assertion was declared in.
* - nLine = The line number the assertion was declared at.
*
* Returns:
* Nothing.
*
* Side effects:
* Characters written to UART1.
*/
void TrAssertFailed(PCSTR pszFile, INT32 nLine)
{
static DECLARE_STRING8_CONST(szMessage, "*** ASSERTION FAILED at %s:%d\n");
TrPrintf8(szMessage, pszFile, nLine);
}
/*
* Puts the CPU into a loop where it blinks the green ACTIVITY light forever.
*
* Parameters:
* None.
*
* Returns:
* DOES NOT RETURN!
*
* Side effects:
* GPIO 16 configured for output and turns on and off indefinitely.
*/
void TrInfiniBlink(void)
{
register UINT32 ra;
flush_trace();
ra = llIORead(GPFSEL1_REG);
ra &= GP_FUNC_MASK(6); /* GPIO 16 - connects to green ACTIVITY LED */
ra |= GP_FUNC_BITS(6, GP_PIN_OUTPUT); /* output in all circumstances */
llIOWrite(GPFSEL1_REG, ra);
for(;;)
{
llIOWrite(GPSET0_REG, GP_BIT(16));
llIODelay(0x100000);
llIOWrite(GPCLR0_REG, GP_BIT(16));
llIODelay(0x100000);
}
}

43
tools/Makefile Normal file
View File

@ -0,0 +1,43 @@
#
# This file is part of the COMROGUE Operating System for Raspberry Pi
#
# Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
# All rights reserved.
#
# This program is free for commercial and non-commercial use as long as the following conditions are
# adhered to.
#
# Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
# in the code are not to be removed.
#
# 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.
#
# THIS SOFTWARE IS 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 HOLDER 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.
#
# "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
MAKEFLAGS += -rR
all: pidl
pidl:
(cd pidl && perl Makefile.PL && make)
clean:
(if [ -f pidl/Makefile ]; then make -C pidl clean; fi)
-rm pidl/Makefile.old
.PHONY: pidl

6
tools/README Normal file
View File

@ -0,0 +1,6 @@
Notes regarding the contents of this directory:
pidl
----
This utility was taken from the Samba 4 sources (git://git.samba.org/samba.git, subdirectory pidl/) and
modified for use with COMROGUE. It and all modifications made to it are distributable under the GNU GPL.

41
tools/pidl/MANIFEST Normal file
View File

@ -0,0 +1,41 @@
MANIFEST
tests/parse_idl.pl
tests/Util.pm
tests/ndr_refptr.pl
tests/ndr_string.pl
tests/ndr_simple.pl
tests/ndr_align.pl
tests/ndr_alloc.pl
tests/ndr_array.pl
tests/ndr.pl
tests/samba-ndr.pl
tests/util.pl
tests/test_util.pl
tests/ndr_represent.pl
tests/ndr_compat.pl
tests/ndr_fullptr.pl
tests/ndr_tagtype.pl
tests/header.pl
lib/Parse/Pidl/Samba3/ClientNDR.pm
lib/Parse/Pidl/Samba3/ServerNDR.pm
lib/Parse/Pidl/Samba4/NDR/Server.pm
lib/Parse/Pidl/Samba4/NDR/Parser.pm
lib/Parse/Pidl/Samba4/NDR/Client.pm
lib/Parse/Pidl/Samba4/Header.pm
lib/Parse/Pidl/Samba4/TDR.pm
lib/Parse/Pidl/Samba4/Template.pm
lib/Parse/Pidl/Samba4.pm
lib/Parse/Pidl/Wireshark/Conformance.pm
lib/Parse/Pidl/Wireshark/NDR.pm
lib/Parse/Pidl/Typelist.pm
lib/Parse/Pidl/Dump.pm
lib/Parse/Pidl/Compat.pm
lib/Parse/Pidl/Util.pm
lib/Parse/Pidl/NDR.pm
lib/Parse/Pidl.pm
Makefile.PL
idl.yp
TODO
README
pidl
META.yml

18
tools/pidl/META.yml Normal file
View File

@ -0,0 +1,18 @@
name: Parse-Pidl
abstract: Generate parsers / DCE/RPC-clients from IDL
author:
- Andrew Tridgell <tridge@samba.org>
- Jelmer Vernooij <jelmer@samba.org>
- Stefan Metzmacher <metze@samba.org>
- Tim Potter <tpot@samba.org>
license: gplv3
installdirs: site
homepage: http://www.samba.org/
bugtracker: http://bugzilla.samba.org/
requires:
Parse::Yapp: 0
recommends:
Data::Dumper: 0
meta-spec:
version: 1.3
url: http://module-build.sourceforge.net/META-spec-v1.3.html

17
tools/pidl/Makefile.PL Executable file
View File

@ -0,0 +1,17 @@
use ExtUtils::MakeMaker;
WriteMakefile(
'NAME' => 'Parse::Pidl',
'VERSION_FROM' => 'lib/Parse/Pidl.pm',
'EXE_FILES' => [ 'pidl' ],
'test' => { 'TESTS' => 'tests/*.pl' }
);
sub MY::postamble {
<<'EOT';
lib/Parse/Pidl/IDL.pm: idl.yp
yapp -m 'Parse::Pidl::IDL' -o lib/Parse/Pidl/IDL.pm idl.yp
lib/Parse/Pidl/Expr.pm: expr.yp
yapp -m 'Parse::Pidl::Expr' -o lib/Parse/Pidl/Expr.pm expr.yp
EOT
}

63
tools/pidl/README Normal file
View File

@ -0,0 +1,63 @@
Introduction:
=============
This directory contains the source code of the pidl (Perl IDL)
compiler for Samba 4.
The main sources for pidl are available using Git as part of
the combined Samba 3 / Samba 4 tree. Use:
git clone git://git.samba.org/samba.git
Pidl works by building a parse tree from a .pidl file (a simple
dump of it's internal parse tree) or a .idl file
(a file format mostly like the IDL file format midl uses).
The IDL file parser is in idl.yp (a yacc file converted to
perl code by yapp)
After a parse tree is present, pidl will call one of it's backends
(which one depends on the options given on the command-line). Here is
a list of current backends:
Standalone installation:
========================
Run Makefile.PL to generate the Makefile.
Then run "make install" (as root) to install.
Internals overview:
===================
-- Generic --
Parse::Pidl::Dump - Converts the parse tree back to an IDL file
Parse::Pidl::Samba4::Header - Generates header file with data structures defined in IDL file
Parse::Pidl::NDR - Generates intermediate datastructures for use by NDR parses/generators
Parse::Pidl::ODL - Generates IDL structures from ODL structures for use in the NDR parser generator
Parse::Pidl::Test - Utility functions for use in pidl's testsuite
-- Samba NDR --
Parse::Pidl::Samba4::NDR::Client - Generates client call functions in C using the NDR parser
Parse::Pidl::Samba4::NDR::Parser - Generates pull/push functions for parsing NDR
Parse::Pidl::Samba4::NDR::Server - Generates server side implementation in C
Parse::Pidl::Samba4::TDR - Parser generator for the "Trivial Data Representation"
Parse::Pidl::Samba4::Template - Generates stubs in C for server implementation
Parse::Pidl::Samba4::Python - Generates bindings for Python
-- Samba COM / DCOM --
Parse::Pidl::Samba4::COM::Proxy - Generates proxy object for DCOM (client-side)
Parse::Pidl::Samba4::COM::Stub - Generates stub call handler for DCOM (server-side)
Parse::Pidl::Samba4::COM::Header - Generates headers for COM
-- Wireshark --
Parse::Pidl::Wireshark::NDR - Generates a parser for the Wireshark network sniffer
Parse::Pidl::Wireshark::Conformance - Reads conformance files containing additional data for generating Wireshark parsers
-- Utility modules --
Parse::Pidl::Util - Misc utility functions used by *.pm and pidl.pl
Parse::Pidl::Typelist - Utility functions for keeping track of known types and their representation in C
Tips for hacking on pidl:
- Look at the pidl's parse tree by using the --keep option and looking
at the generated .pidl file.
- The various backends have a lot in common, if you don't understand how one
implements something, look at the others
- See pidl(1) and the documentation on midl
- See 'info bison' and yapp(1) for information on the file format of idl.yp

44
tools/pidl/TODO Normal file
View File

@ -0,0 +1,44 @@
- warn when union instances don't have a discriminant
- true multiple dimension array / strings in arrays support
- compatibility mode for generating MIDL-readable data:
- strip out pidl-specific properties
- make bitmap an optional attribute on enum
- support nested elements
- support typedefs properly (e.g. allow "typedef void **bla;")
- make typedefs generate real typedefs
- improve represent_as(): allow it to be used for arrays and other complex
types
- --explain-ndr option that dumps out parse tree ?
- seperate tables for NDR and DCE/RPC
- maybe no tables for NDR at all? we only need them for ndrdump
and that can use dlsym()
- allow data structures outside of interfaces
- mem_ctx in the interface rather than as struct ndr member.
- real typelibs
- fix [in,out] handling and allocation for samba3:
- add inout
- make NULL to mean "allocate me"
- remove NDR_AUTO_REF_ALLOC flag
- automatic test generator based on IDL pointer types
- support converting structs to tuples in Python rather than objects
- convert structs with a single mattering member to that member directly, e.g.:
struct bar {
int size;
[size_is(size)] uint32 *array;
};
should be converted to an array of uint32's
- python: fill in size members automatically in some places if the struct isn't being returned
(so we don't have to cope with the array growing)

202
tools/pidl/expr.yp Normal file
View File

@ -0,0 +1,202 @@
# expr.yp
# Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU GPL
#
%left '->'
%right '!' '~'
%left '*' '/' '%'
%left '+' '-'
%left '<<' '>>'
%left '>' '<'
%left '==' '!='
%left '&'
%left '|'
%left '&&'
%left '||'
%left '?' ':'
%left NEG DEREF ADDROF INV
%left '.'
%%
exp:
NUM
|
TEXT { "\"$_[1]\"" }
|
func
|
var
|
'~' exp %prec INV { "~$_[2]" }
|
exp '+' exp { "$_[1] + $_[3]" }
|
exp '-' exp { "$_[1] - $_[3]" }
|
exp '*' exp { "$_[1] * $_[3]" }
|
exp '%' exp { "$_[1] % $_[3]" }
|
exp '<' exp { "$_[1] < $_[3]" }
|
exp '>' exp { "$_[1] > $_[3]" }
|
exp '|' exp { "$_[1] | $_[3]" }
|
exp '==' exp { "$_[1] == $_[3]" }
|
exp '<=' exp { "$_[1] <= $_[3]" }
|
exp '=>' exp { "$_[1] => $_[3]" }
|
exp '<<' exp { "$_[1] << $_[3]" }
|
exp '>>' exp { "$_[1] >> $_[3]" }
|
exp '!=' exp { "$_[1] != $_[3]" }
|
exp '||' exp { "$_[1] || $_[3]" }
|
exp '&&' exp { "$_[1] && $_[3]" }
|
exp '&' exp { "$_[1] & $_[3]" }
|
exp '?' exp ':' exp { "$_[1]?$_[3]:$_[5]" }
|
'~' exp { "~$_[1]" }
|
'!' exp { "not $_[1]" }
|
exp '/' exp { "$_[1] / $_[3]" }
|
'-' exp %prec NEG { "-$_[2]" }
|
'&' exp %prec ADDROF { "&$_[2]" }
|
exp '^' exp { "$_[1]^$_[3]" }
|
'(' exp ')' { "($_[2])" }
;
possible_pointer:
VAR { $_[0]->_Lookup($_[1]) }
|
'*' possible_pointer %prec DEREF { $_[0]->_Dereference($_[2]); "*$_[2]" }
;
var:
possible_pointer { $_[0]->_Use($_[1]) }
|
var '.' VAR { $_[0]->_Use("$_[1].$_[3]") }
|
'(' var ')' { "($_[2])" }
|
var '->' VAR { $_[0]->_Use("*$_[1]"); $_[1]."->".$_[3] }
;
func:
VAR '(' opt_args ')' { "$_[1]($_[3])" }
;
opt_args:
#empty
{ "" }
|
args
;
exp_or_possible_pointer:
exp
|
possible_pointer
;
args:
exp_or_possible_pointer
|
exp_or_possible_pointer ',' args { "$_[1], $_[3]" }
;
%%
package Parse::Pidl::Expr;
sub _Lexer {
my($parser)=shift;
$parser->YYData->{INPUT}=~s/^[ \t]//;
for ($parser->YYData->{INPUT}) {
if (s/^(0x[0-9A-Fa-f]+)//) {
$parser->YYData->{LAST_TOKEN} = $1;
return('NUM',$1);
}
if (s/^([0-9]+(?:\.[0-9]+)?)//) {
$parser->YYData->{LAST_TOKEN} = $1;
return('NUM',$1);
}
if (s/^([A-Za-z_][A-Za-z0-9_]*)//) {
$parser->YYData->{LAST_TOKEN} = $1;
return('VAR',$1);
}
if (s/^\"(.*?)\"//) {
$parser->YYData->{LAST_TOKEN} = $1;
return('TEXT',$1);
}
if (s/^(==|!=|<=|>=|->|\|\||<<|>>|&&)//s) {
$parser->YYData->{LAST_TOKEN} = $1;
return($1,$1);
}
if (s/^(.)//s) {
$parser->YYData->{LAST_TOKEN} = $1;
return($1,$1);
}
}
}
sub _Use($$)
{
my ($self, $x) = @_;
if (defined($self->YYData->{USE})) {
return $self->YYData->{USE}->($x);
}
return $x;
}
sub _Lookup($$)
{
my ($self, $x) = @_;
return $self->YYData->{LOOKUP}->($x);
}
sub _Dereference($$)
{
my ($self, $x) = @_;
if (defined($self->YYData->{DEREFERENCE})) {
$self->YYData->{DEREFERENCE}->($x);
}
}
sub _Error($)
{
my ($self) = @_;
if (defined($self->YYData->{LAST_TOKEN})) {
$self->YYData->{ERROR}->("Parse error in `".$self->YYData->{FULL_INPUT}."' near `". $self->YYData->{LAST_TOKEN} . "'");
} else {
$self->YYData->{ERROR}->("Parse error in `".$self->YYData->{FULL_INPUT}."'");
}
}
sub Run {
my($self, $data, $error, $lookup, $deref, $use) = @_;
$self->YYData->{FULL_INPUT} = $data;
$self->YYData->{INPUT} = $data;
$self->YYData->{LOOKUP} = $lookup;
$self->YYData->{DEREFERENCE} = $deref;
$self->YYData->{ERROR} = $error;
$self->YYData->{USE} = $use;
return $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error);
}

699
tools/pidl/idl.yp Normal file
View File

@ -0,0 +1,699 @@
########################
# IDL Parse::Yapp parser
# Copyright (C) Andrew Tridgell <tridge@samba.org>
# released under the GNU GPL version 3 or later
# the precedence actually doesn't matter at all for this grammar, but
# by providing a precedence we reduce the number of conflicts
# enormously
%left '-' '+' '&' '|' '*' '>' '.' '/' '(' ')' '[' ',' ';'
################
# grammar
%%
idl:
#empty { {} }
|
idl interface { push(@{$_[1]}, $_[2]); $_[1] }
|
idl coclass { push(@{$_[1]}, $_[2]); $_[1] }
|
idl import { push(@{$_[1]}, $_[2]); $_[1] }
|
idl include { push(@{$_[1]}, $_[2]); $_[1] }
|
idl importlib { push(@{$_[1]}, $_[2]); $_[1] }
|
idl cpp_quote { push(@{$_[1]}, $_[2]); $_[1] }
;
import:
'import' commalist ';'
{{
"TYPE" => "IMPORT",
"PATHS" => $_[2],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
include:
'include' commalist ';'
{{
"TYPE" => "INCLUDE",
"PATHS" => $_[2],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
importlib:
'importlib' commalist ';'
{{
"TYPE" => "IMPORTLIB",
"PATHS" => $_[2],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
commalist:
text { [ $_[1] ] }
|
commalist ',' text { push(@{$_[1]}, $_[3]); $_[1] }
;
coclass:
property_list 'coclass' identifier '{' interface_names '}' optional_semicolon
{{
"TYPE" => "COCLASS",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"DATA" => $_[5],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
interface_names:
#empty { {} }
|
interface_names 'interface' identifier ';' { push(@{$_[1]}, $_[2]); $_[1] }
;
interface:
property_list 'interface' identifier base_interface '{' definitions '}' optional_semicolon
{{
"TYPE" => "INTERFACE",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"BASE" => $_[4],
"DATA" => $_[6],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
base_interface:
#empty
|
':' identifier { $_[2] }
;
cpp_quote:
'cpp_quote' '(' text ')'
{{
"TYPE" => "CPP_QUOTE",
"DATA" => $_[3],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
definitions:
definition { [ $_[1] ] }
|
definitions definition { push(@{$_[1]}, $_[2]); $_[1] }
;
definition:
function
|
const
|
typedef
|
typedecl
|
cpp_quote
;
const:
'const' identifier pointers identifier '=' anytext ';'
{{
"TYPE" => "CONST",
"DTYPE" => $_[2],
"POINTERS" => $_[3],
"NAME" => $_[4],
"VALUE" => $_[6],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
|
'const' identifier pointers identifier array_len '=' anytext ';'
{{
"TYPE" => "CONST",
"DTYPE" => $_[2],
"POINTERS" => $_[3],
"NAME" => $_[4],
"ARRAY_LEN" => $_[5],
"VALUE" => $_[7],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
function:
property_list type identifier '(' element_list2 ')' ';'
{{
"TYPE" => "FUNCTION",
"NAME" => $_[3],
"RETURN_TYPE" => $_[2],
"PROPERTIES" => $_[1],
"ELEMENTS" => $_[5],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
typedef:
property_list 'typedef' optional_const type pointers identifier array_len ';'
{{
"TYPE" => "TYPEDEF",
"PROPERTIES" => $_[1],
"CONST" => $_[3],
"NAME" => $_[6],
"DATA" => $_[4],
"POINTERS" => $_[5],
"ARRAY_LEN" => $_[7],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
usertype:
struct
|
union
|
enum
|
bitmap
|
pipe
;
typedecl:
usertype ';' { $_[1] }
;
sign:
'signed'
|
'unsigned'
;
existingtype:
sign identifier { ($_[1]?$_[1]:"signed") ." $_[2]" }
|
identifier
;
type:
usertype
|
existingtype
|
void { "void" }
;
enum_body:
'{' enum_elements '}' { $_[2] }
;
opt_enum_body:
#empty
|
enum_body
;
enum:
property_list 'enum' optional_identifier opt_enum_body
{{
"TYPE" => "ENUM",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
enum_elements:
enum_element { [ $_[1] ] }
|
enum_elements ',' enum_element { push(@{$_[1]}, $_[3]); $_[1] }
;
enum_element:
identifier
|
identifier '=' anytext { "$_[1]$_[2]$_[3]" }
;
bitmap_body:
'{' opt_bitmap_elements '}' { $_[2] }
;
opt_bitmap_body:
#empty
|
bitmap_body
;
bitmap:
property_list 'bitmap' optional_identifier opt_bitmap_body
{{
"TYPE" => "BITMAP",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
bitmap_elements:
bitmap_element { [ $_[1] ] }
|
bitmap_elements ',' bitmap_element { push(@{$_[1]}, $_[3]); $_[1] }
;
opt_bitmap_elements:
#empty
|
bitmap_elements
;
bitmap_element:
identifier '=' anytext { "$_[1] ( $_[3] )" }
;
struct_body:
'{' element_list1 '}' { $_[2] }
;
opt_struct_body:
#empty
|
struct_body
;
struct:
property_list 'struct' optional_identifier opt_struct_body
{{
"TYPE" => "STRUCT",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
empty_element:
property_list ';'
{{
"NAME" => "",
"TYPE" => "EMPTY",
"PROPERTIES" => $_[1],
"POINTERS" => 0,
"ARRAY_LEN" => [],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
base_or_empty:
base_element ';'
|
empty_element;
optional_base_element:
property_list base_or_empty { $_[2]->{PROPERTIES} = FlattenHash([$_[1],$_[2]->{PROPERTIES}]); $_[2] }
;
union_elements:
#empty
|
union_elements optional_base_element { push(@{$_[1]}, $_[2]); $_[1] }
;
union_body:
'{' union_elements '}' { $_[2] }
;
opt_union_body:
#empty
|
union_body
;
union:
property_list 'union' optional_identifier opt_union_body
{{
"TYPE" => "UNION",
"PROPERTIES" => $_[1],
"NAME" => $_[3],
"ELEMENTS" => $_[4],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
base_element:
property_list type pointers identifier array_len
{{
"NAME" => $_[4],
"TYPE" => $_[2],
"PROPERTIES" => $_[1],
"POINTERS" => $_[3],
"ARRAY_LEN" => $_[5],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
pointers:
#empty
{ 0 }
|
pointers '*' { $_[1]+1 }
;
pipe:
property_list 'pipe' type
{{
"TYPE" => "PIPE",
"PROPERTIES" => $_[1],
"NAME" => undef,
"DATA" => {
"TYPE" => "STRUCT",
"PROPERTIES" => $_[1],
"NAME" => undef,
"ELEMENTS" => [{
"NAME" => "count",
"PROPERTIES" => $_[1],
"POINTERS" => 0,
"ARRAY_LEN" => [],
"TYPE" => "uint3264",
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
},{
"NAME" => "array",
"PROPERTIES" => $_[1],
"POINTERS" => 0,
"ARRAY_LEN" => [ "count" ],
"TYPE" => $_[3],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}],
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
},
"FILE" => $_[0]->YYData->{FILE},
"LINE" => $_[0]->YYData->{LINE},
}}
;
element_list1:
#empty
{ [] }
|
element_list1 base_element ';' { push(@{$_[1]}, $_[2]); $_[1] }
;
optional_const:
#empty { 0 }
|
'const' { 1 }
;
element_list2:
#empty
|
'void'
|
optional_const base_element { [ $_[2] ] }
|
element_list2 ',' optional_const base_element { push(@{$_[1]}, $_[4]); $_[1] }
;
array_len:
#empty { [] }
|
'[' ']' array_len { push(@{$_[3]}, "*"); $_[3] }
|
'[' anytext ']' array_len { push(@{$_[4]}, "$_[2]"); $_[4] }
;
property_list:
#empty
|
property_list '[' properties ']' { FlattenHash([$_[1],$_[3]]); }
;
properties:
property { $_[1] }
|
properties ',' property { FlattenHash([$_[1], $_[3]]); }
;
property:
identifier {{ "$_[1]" => "1" }}
|
identifier '(' commalisttext ')' {{ "$_[1]" => "$_[3]" }}
;
commalisttext:
anytext
|
commalisttext ',' anytext { "$_[1],$_[3]" }
;
anytext:
#empty
{ "" }
|
identifier
|
constant
|
text
|
anytext '-' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '.' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '*' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '>' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '<' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '|' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '&' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '/' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '?' anytext { "$_[1]$_[2]$_[3]" }
|
anytext ':' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '=' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '+' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '~' anytext { "$_[1]$_[2]$_[3]" }
|
anytext '(' commalisttext ')' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
|
anytext '{' commalisttext '}' anytext { "$_[1]$_[2]$_[3]$_[4]$_[5]" }
;
identifier:
IDENTIFIER
;
optional_identifier:
#empty { undef }
|
IDENTIFIER
;
constant:
CONSTANT
;
text:
TEXT { "\"$_[1]\"" }
;
optional_semicolon:
#empty
|
';'
;
#####################################
# start code
%%
use Parse::Pidl qw(error);
#####################################################################
# flatten an array of hashes into a single hash
sub FlattenHash($)
{
my $a = shift;
my %b;
for my $d (@{$a}) {
for my $k (keys %{$d}) {
$b{$k} = $d->{$k};
}
}
return \%b;
}
#####################################################################
# traverse a perl data structure removing any empty arrays or
# hashes and any hash elements that map to undef
sub CleanData($)
{
sub CleanData($);
my($v) = shift;
return undef if (not defined($v));
if (ref($v) eq "ARRAY") {
foreach my $i (0 .. $#{$v}) {
CleanData($v->[$i]);
}
# this removes any undefined elements from the array
@{$v} = grep { defined $_ } @{$v};
} elsif (ref($v) eq "HASH") {
foreach my $x (keys %{$v}) {
CleanData($v->{$x});
if (!defined $v->{$x}) {
delete($v->{$x});
next;
}
}
}
return $v;
}
sub _Error {
if (exists $_[0]->YYData->{ERRMSG}) {
error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
delete $_[0]->YYData->{ERRMSG};
return;
}
my $last_token = $_[0]->YYData->{LAST_TOKEN};
error($_[0]->YYData, "Syntax error near '$last_token'");
}
sub _Lexer($)
{
my($parser)=shift;
$parser->YYData->{INPUT} or return('',undef);
again:
$parser->YYData->{INPUT} =~ s/^[ \t]*//;
for ($parser->YYData->{INPUT}) {
if (/^\#/) {
# Linemarker format is described at
# http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html
if (s/^\# (\d+) \"(.*?)\"(( \d+){1,4}|)//) {
$parser->YYData->{LINE} = $1-1;
$parser->YYData->{FILE} = $2;
goto again;
}
if (s/^\#line (\d+) \"(.*?)\"( \d+|)//) {
$parser->YYData->{LINE} = $1-1;
$parser->YYData->{FILE} = $2;
goto again;
}
if (s/^(\#.*)$//m) {
goto again;
}
}
if (s/^(\n)//) {
$parser->YYData->{LINE}++;
goto again;
}
if (s/^\"(.*?)\"//) {
$parser->YYData->{LAST_TOKEN} = $1;
return('TEXT',$1);
}
if (s/^(\d+)(\W|$)/$2/) {
$parser->YYData->{LAST_TOKEN} = $1;
return('CONSTANT',$1);
}
if (s/^([\w_]+)//) {
$parser->YYData->{LAST_TOKEN} = $1;
if ($1 =~
/^(coclass|interface|import|importlib
|include|cpp_quote|typedef
|union|struct|enum|bitmap|pipe
|void|const|unsigned|signed)$/x) {
return $1;
}
return('IDENTIFIER',$1);
}
if (s/^(.)//s) {
$parser->YYData->{LAST_TOKEN} = $1;
return($1,$1);
}
}
}
sub parse_string
{
my ($data,$filename) = @_;
my $self = new Parse::Pidl::IDL;
$self->YYData->{FILE} = $filename;
$self->YYData->{INPUT} = $data;
$self->YYData->{LINE} = 0;
$self->YYData->{LAST_TOKEN} = "NONE";
my $idl = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error );
return CleanData($idl);
}
sub parse_file($$)
{
my ($filename,$incdirs) = @_;
my $saved_delim = $/;
undef $/;
my $cpp = $ENV{CPP};
my $options = "";
if (! defined $cpp) {
if (defined $ENV{CC}) {
$cpp = "$ENV{CC}";
$options = "-E";
} else {
$cpp = "cpp";
}
}
my $includes = join('',map { " -I$_" } @$incdirs);
my $data = `$cpp $options -D__PIDL__$includes -xc "$filename"`;
$/ = $saved_delim;
return parse_string($data, $filename);
}

View File

@ -0,0 +1,44 @@
###################################################
# package to parse IDL files and generate code for
# rpc functions in Samba
# Copyright tridge@samba.org 2000-2003
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(warning error fatal $VERSION);
use strict;
use vars qw ( $VERSION );
$VERSION = '0.02';
sub warning
{
my ($l,$m) = @_;
if ($l) {
print STDERR "$l->{FILE}:$l->{LINE}: ";
}
print STDERR "warning: $m\n";
}
sub error
{
my ($l,$m) = @_;
if ($l) {
print STDERR "$l->{FILE}:$l->{LINE}: ";
}
print STDERR "error: $m\n";
}
sub fatal($$)
{
my ($e,$s) = @_;
die("$e->{FILE}:$e->{LINE}: $s\n");
}
1;

View File

@ -0,0 +1,319 @@
# COM Header generation
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Modifications (C) 2013 Eric J. Bowersox <erbo@erbosoft.com>
package Parse::Pidl::COMROGUE::Header;
use Parse::Pidl::Typelist qw(mapTypeName maybeMapScalarType is_struct);
use Parse::Pidl::Util qw(has_property is_constant);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
sub stripquotes($)
{
my $str = shift;
$str =~ s/^\"//;
$str =~ s/\"$//;
return $str;
}
sub GetArgumentProtoList($)
{
my $f = shift;
my $res = "";
my $first = 1;
foreach my $a (@{$f->{ELEMENTS}}) {
$res .= ", " unless $first;
$first = 0;
$res .= maybeMapScalarType($a->{TYPE}) . " ";
my $l = $a->{POINTERS};
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($a->{TYPE}));
foreach my $i (1..$l) {
$res .= "*";
}
if (defined $a->{ARRAY_LEN}[0] && !is_constant($a->{ARRAY_LEN}[0]) &&
!$a->{POINTERS}) {
$res .= "*";
}
$res .= $a->{NAME};
if (defined $a->{ARRAY_LEN}[0] && is_constant($a->{ARRAY_LEN}[0])) {
$res .= "[$a->{ARRAY_LEN}[0]]";
}
}
return undef if $first;
return $res;
}
sub GetArgumentList($)
{
my $f = shift;
my $res = "";
my $first = 1;
foreach (@{$f->{ELEMENTS}}) {
$res .= ", " unless $first;
$first = 0;
$res .= "$_->{NAME}";
}
return undef if $first;
return $res;
}
sub MethodsDefinition($)
{
my $interface = shift;
my $res = "";
$res .= "#define METHODS_" . $interface->{NAME} . " \\\n";
if (defined($interface->{BASE})) {
$res .= "\tINHERIT_METHODS(METHODS_" . $interface->{BASE} . ") \\\n";
}
my $data = $interface->{DATA};
foreach my $d (@{$data}) {
next unless ($d->{TYPE} eq "FUNCTION");
if ($d->{RETURN_TYPE} eq "HRESULT") {
$res .= "\tSTDMETHOD($d->{NAME})";
} else {
$res .= "\tSTDMETHOD_($d->{NAME}," . $d->{RETURN_TYPE} . ")";
}
my $args = GetArgumentProtoList($d);
if (defined($args)) {
$res .= "(THIS_($interface->{NAME}) $args) PURE;\\\n";
} else {
$res .= "(THIS($interface->{NAME})) PURE;\\\n";
}
}
$res .= "\tEND_METHODS\n\n";
return $res;
}
sub MakeGUIDDef($$$)
{
my $t = shift;
my $name = shift;
my $uuid = shift;
my @uuidparts = split(/-/, $uuid);
my $b1 = substr($uuidparts[3], 0, 2);
my $b2 = substr($uuidparts[3], 2, 2);
my $b3 = substr($uuidparts[4], 0, 2);
my $b4 = substr($uuidparts[4], 2, 2);
my $b5 = substr($uuidparts[4], 4, 2);
my $b6 = substr($uuidparts[4], 6, 2);
my $b7 = substr($uuidparts[4], 8, 2);
my $b8 = substr($uuidparts[4], 10, 2);
return "DEFINE_$t(${t}_$name, 0x$uuidparts[0], 0x$uuidparts[1], 0x$uuidparts[2], " .
"0x$b1, 0x$b2, 0x$b3, 0x$b4, 0x$b5, 0x$b6, 0x$b7, 0x$b8);\n\n";
}
sub ParseImports($)
{
my $imp = shift;
my $res = "";
my $seen = 0;
foreach my $p (@{$imp->{PATHS}}) {
my $header = $p;
$header =~ s/\.idl/\.h/;
$header =~ s/^\"/</;
$header =~ s/\"$/>/;
$res .= "#include $header\n";
$seen = 1;
}
$res .= "\n" if $seen;
return $res;
}
sub ParseElement($$)
{
my $prefix = shift;
my $element = shift;
my $res = "";
$res .= $prefix . maybeMapScalarType($element->{TYPE}) . " " . $element->{NAME};
if (defined($element->{ARRAY_LEN})) {
foreach my $l (@{$element->{ARRAY_LEN}}) {
$res .= "[" . $l . "]";
}
}
$res .= ";\n";
return $res;
}
sub ParseTypedef($)
{
my $def = shift;
my $res = "";
$res .= "typedef ";
$res .= "const " if ($def->{CONST});
if (ref($def->{DATA}) ne "HASH") {
$res .= maybeMapScalarType($def->{DATA}) . " ";
} else {
if (is_struct($def->{DATA})) {
$res .= mapTypeName($def->{DATA}) . " {\n";
foreach my $elt (@{$def->{DATA}->{ELEMENTS}}) {
$res .= ParseElement("\t", $elt);
}
$res .= "} ";
} else {
$res .= mapTypeName($def->{DATA}) . " ";
}
}
my $l = $def->{POINTERS};
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($def->{TYPE}));
foreach my $i (1..$l) {
$res .= "*";
}
$res .= $def->{NAME} . ";\n";
return $res;
}
sub ParseTypedefs($)
{
my $if = shift;
my $res = "";
my $count = 0;
foreach my $d (@{$if->{DATA}}) {
$res .= stripquotes($d->{DATA}) . "\n" if ($d->{TYPE} eq "CPP_QUOTE");
next unless ($d->{TYPE} eq "TYPEDEF");
++$count;
$res .= ParseTypedef($d);
}
$res .= "\n";
return "" if ($count == 0);
return $res;
}
sub ParseInterface($)
{
my $if = shift;
my $res;
my $d;
$res .= "/*---------------------------------------------------------------\n";
$res .= " * Interface $if->{NAME}\n";
$res .= " *---------------------------------------------------------------\n";
$res .= " */\n\n";
$res .= MakeGUIDDef("IID", $if->{NAME}, $if->{PROPERTIES}->{uuid});
$res .= MethodsDefinition($if);
if (defined($if->{BASE})) {
$res .= "BEGIN_INTERFACE_(" . $if->{NAME} . ", " . $if->{BASE} . ")\n";
} else {
$res .= "BEGIN_INTERFACE(" . $if->{NAME} . ")\n";
}
$res .= "\tMETHODS_" . $if->{NAME} . "\n";
$res .= "END_INTERFACE(" . $if->{NAME} . ")\n\n";
foreach $d (@{$if->{DATA}}) {
$res .= stripquotes($d->{DATA}) . "\n" if ($d->{TYPE} eq "CPP_QUOTE");
$res .= ParseTypedef($d) if ($d->{TYPE} eq "TYPEDEF");
}
$res .= "\n#ifdef CINTERFACE\n\n";
foreach $d (@{$if->{DATA}}) {
next unless ($d->{TYPE} eq "FUNCTION");
my $args = GetArgumentList($d);
if (defined($args)) {
$res .= "#define $if->{NAME}_$d->{NAME}(pInterface, $args) \\\n";
$res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(pInterface, $args)\n";
} else {
$res .= "#define $if->{NAME}_$d->{NAME}(pInterface) \\\n";
$res .= "\t(*((pInterface)->pVTable->$d->{NAME}))(pInterface)\n";
}
}
$res .= "\n#endif /* CINTERFACE */\n\n";
return $res;
}
sub ParseCoClass($)
{
my ($c) = @_;
my $res = "";
$res .= "/*---------------------------------------------------------------\n";
$res .= " * Class $c->{NAME}\n";
$res .= " *---------------------------------------------------------------\n";
$res .= " */\n\n";
$res .= MakeGUIDDef("CLSID", $c->{NAME}, $c->{PROPERTIES}->{uuid});
if (has_property($c, "progid")) {
$res .= "#define PROGID_" . $c->{NAME} . " \"$c->{PROPERTIES}->{progid}\"\n";
}
$res .= "\n";
return $res;
}
sub Parse($$$)
{
my ($idl,$basename, $srcfile) = @_;
my $res = "";
my $has_obj = 0;
$res .= "/* COMROGUE: Autogenerated from IDL file $srcfile */\n\n";
my $include_sym = "__" . uc($basename) . "_H_INCLUDED";
$res .= "#ifndef $include_sym\n" .
"#define $include_sym\n\n" .
"#ifndef __ASM__\n\n";
my $want_macro_headers = 1;
foreach (@{$idl})
{
if ($_->{TYPE} eq "CPP_QUOTE") {
$res .= stripquotes($_->{DATA}) . "\n";
}
if ($_->{TYPE} eq "IMPORT") {
$res .= ParseImports($_);
}
if ($_->{TYPE} eq "INTERFACE") {
if (has_property($_, "object")) {
if ($want_macro_headers) {
$res .= "#include <comrogue/object_definition_macros.h>\n\n";
$want_macro_headers = 0;
}
$res .= ParseInterface($_);
} else {
$res .= ParseTypedefs($_);
}
$has_obj = 1;
}
if ($_->{TYPE} eq "COCLASS") {
if ($want_macro_headers) {
$res .= "#include <comrogue/object_definition_macros.h>\n\n";
$want_macro_headers = 0;
}
$res.=ParseCoClass($_);
$has_obj = 1;
}
}
$res .= "#endif /* __ASM__ */\n\n";
$res .= "#endif /* $include_sym */\n";
return $res if ($has_obj);
return undef;
}
1;

View File

@ -0,0 +1,52 @@
###################################################
# C utility functions for pidl
# Copyright jelmer@samba.org 2005-2007
# released under the GNU GPL
package Parse::Pidl::CUtil;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(get_pointer_to get_value_of get_array_element);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
sub get_pointer_to($)
{
my $var_name = shift;
if ($var_name =~ /^\*(.*)$/) {
return $1;
} elsif ($var_name =~ /^\&(.*)$/) {
return "&($var_name)";
} else {
return "&$var_name";
}
}
sub get_value_of($)
{
my $var_name = shift;
if ($var_name =~ /^\&(.*)$/) {
return $1;
} else {
return "*$var_name";
}
}
sub get_array_element($$)
{
my ($var_name, $idx) = @_;
if ($var_name =~ /^\*.*$/) {
$var_name = "($var_name)";
} elsif ($var_name =~ /^\&.*$/) {
$var_name = "($var_name)";
}
return "$var_name"."[$idx]";
}
1;

View File

@ -0,0 +1,168 @@
###################################################
# IDL Compatibility checker
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Compat;
use Parse::Pidl qw(warning);
use Parse::Pidl::Util qw(has_property);
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
my %supported_properties = (
# interface
"helpstring" => ["INTERFACE", "FUNCTION"],
"version" => ["INTERFACE"],
"uuid" => ["INTERFACE"],
"endpoint" => ["INTERFACE"],
"pointer_default" => ["INTERFACE"],
"no_srv_register" => ["INTERFACE"],
# dcom
"object" => ["INTERFACE"],
"local" => ["INTERFACE", "FUNCTION"],
"iid_is" => ["ELEMENT"],
"call_as" => ["FUNCTION"],
"idempotent" => ["FUNCTION"],
# function
"in" => ["ELEMENT"],
"out" => ["ELEMENT"],
# pointer
"ref" => ["ELEMENT"],
"ptr" => ["ELEMENT"],
"unique" => ["ELEMENT"],
"ignore" => ["ELEMENT"],
"value" => ["ELEMENT"],
# generic
"public" => ["FUNCTION", "TYPEDEF"],
"nopush" => ["FUNCTION", "TYPEDEF"],
"nopull" => ["FUNCTION", "TYPEDEF"],
"noprint" => ["FUNCTION", "TYPEDEF"],
"nopython" => ["FUNCTION", "TYPEDEF"],
# union
"switch_is" => ["ELEMENT"],
"switch_type" => ["ELEMENT", "TYPEDEF"],
"case" => ["ELEMENT"],
"default" => ["ELEMENT"],
# subcontext
"subcontext" => ["ELEMENT"],
"subcontext_size" => ["ELEMENT"],
# enum
"enum16bit" => ["TYPEDEF"],
"v1_enum" => ["TYPEDEF"],
# bitmap
"bitmap8bit" => ["TYPEDEF"],
"bitmap16bit" => ["TYPEDEF"],
"bitmap32bit" => ["TYPEDEF"],
"bitmap64bit" => ["TYPEDEF"],
# array
"range" => ["ELEMENT"],
"size_is" => ["ELEMENT"],
"string" => ["ELEMENT"],
"noheader" => ["ELEMENT"],
"charset" => ["ELEMENT"],
"length_is" => ["ELEMENT"],
);
sub CheckTypedef($)
{
my ($td) = @_;
if (has_property($td, "nodiscriminant")) {
warning($td, "nodiscriminant property not supported");
}
if ($td->{TYPE} eq "BITMAP") {
warning($td, "converting bitmap to scalar");
#FIXME
}
if (has_property($td, "gensize")) {
warning($td, "ignoring gensize() property. ");
}
if (has_property($td, "enum8bit") and has_property($td, "enum16bit")) {
warning($td, "8 and 16 bit enums not supported, converting to scalar");
#FIXME
}
StripProperties($td);
}
sub CheckElement($)
{
my $e = shift;
if (has_property($e, "noheader")) {
warning($e, "noheader property not supported");
return;
}
if (has_property($e, "subcontext")) {
warning($e, "converting subcontext to byte array");
#FIXME
}
if (has_property($e, "compression")) {
warning($e, "compression() property not supported");
}
if (has_property($e, "sptr")) {
warning($e, "sptr() pointer property not supported");
}
if (has_property($e, "relative")) {
warning($e, "relative() pointer property not supported");
}
if (has_property($e, "relative_short")) {
warning($e, "relative_short() pointer property not supported");
}
if (has_property($e, "flag")) {
warning($e, "ignoring flag() property");
}
if (has_property($e, "value")) {
warning($e, "ignoring value() property");
}
}
sub CheckFunction($)
{
my $fn = shift;
if (has_property($fn, "noopnum")) {
warning($fn, "noopnum not converted. Opcodes will be out of sync.");
}
}
sub CheckInterface($)
{
my $if = shift;
}
sub Check($)
{
my $pidl = shift;
my $nidl = [];
foreach (@{$pidl}) {
push (@$nidl, CheckInterface($_)) if ($_->{TYPE} eq "INTERFACE");
}
}
1;

View File

@ -0,0 +1,294 @@
###################################################
# dump function for IDL structures
# Copyright tridge@samba.org 2000
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
=pod
=head1 NAME
Parse::Pidl::Dump - Dump support
=head1 DESCRIPTION
This module provides functions that can generate IDL code from
internal pidl data structures.
=cut
package Parse::Pidl::Dump;
use Exporter;
use vars qw($VERSION);
$VERSION = '0.01';
@ISA = qw(Exporter);
@EXPORT_OK = qw(DumpType DumpTypedef DumpStruct DumpEnum DumpBitmap DumpUnion DumpFunction);
use strict;
use Parse::Pidl::Util qw(has_property);
my($res);
#####################################################################
# dump a properties list
sub DumpProperties($)
{
my($props) = shift;
my $res = "";
foreach my $d ($props) {
foreach my $k (keys %{$d}) {
if ($k eq "in") {
$res .= "[in] ";
next;
}
if ($k eq "out") {
$res .= "[out] ";
next;
}
if ($k eq "ref") {
$res .= "[ref] ";
next;
}
$res .= "[$k($d->{$k})] ";
}
}
return $res;
}
#####################################################################
# dump a structure element
sub DumpElement($)
{
my($element) = shift;
my $res = "";
(defined $element->{PROPERTIES}) &&
($res .= DumpProperties($element->{PROPERTIES}));
$res .= DumpType($element->{TYPE});
$res .= " ";
for my $i (1..$element->{POINTERS}) {
$res .= "*";
}
$res .= "$element->{NAME}";
foreach (@{$element->{ARRAY_LEN}}) {
$res .= "[$_]";
}
return $res;
}
#####################################################################
# dump a struct
sub DumpStruct($)
{
my($struct) = shift;
my($res);
$res .= "struct ";
if ($struct->{NAME}) {
$res.="$struct->{NAME} ";
}
$res.="{\n";
if (defined $struct->{ELEMENTS}) {
foreach (@{$struct->{ELEMENTS}}) {
$res .= "\t" . DumpElement($_) . ";\n";
}
}
$res .= "}";
return $res;
}
#####################################################################
# dump a struct
sub DumpEnum($)
{
my($enum) = shift;
my($res);
$res .= "enum {\n";
foreach (@{$enum->{ELEMENTS}}) {
if (/^([A-Za-z0-9_]+)[ \t]*\((.*)\)$/) {
$res .= "\t$1 = $2,\n";
} else {
$res .= "\t$_,\n";
}
}
$res.= "}";
return $res;
}
#####################################################################
# dump a struct
sub DumpBitmap($)
{
my($bitmap) = shift;
my($res);
$res .= "bitmap {\n";
foreach (@{$bitmap->{ELEMENTS}}) {
if (/^([A-Za-z0-9_]+)[ \t]*\((.*)\)$/) {
$res .= "\t$1 = $2,\n";
} else {
die ("Bitmap $bitmap->{NAME} has field $_ without proper value");
}
}
$res.= "}";
return $res;
}
#####################################################################
# dump a union element
sub DumpUnionElement($)
{
my($element) = shift;
my($res);
if (has_property($element, "default")) {
$res .= "[default] ;\n";
} else {
$res .= "[case($element->{PROPERTIES}->{case})] ";
$res .= DumpElement($element), if defined($element);
$res .= ";\n";
}
return $res;
}
#####################################################################
# dump a union
sub DumpUnion($)
{
my($union) = shift;
my($res);
(defined $union->{PROPERTIES}) &&
($res .= DumpProperties($union->{PROPERTIES}));
$res .= "union {\n";
foreach my $e (@{$union->{ELEMENTS}}) {
$res .= DumpUnionElement($e);
}
$res .= "}";
return $res;
}
#####################################################################
# dump a type
sub DumpType($)
{
my($data) = shift;
if (ref($data) eq "HASH") {
return DumpStruct($data) if ($data->{TYPE} eq "STRUCT");
return DumpUnion($data) if ($data->{TYPE} eq "UNION");
return DumpEnum($data) if ($data->{TYPE} eq "ENUM");
return DumpBitmap($data) if ($data->{TYPE} eq "BITMAP");
} else {
return $data;
}
}
#####################################################################
# dump a typedef
sub DumpTypedef($)
{
my($typedef) = shift;
my($res);
$res .= "typedef ";
$res .= DumpType($typedef->{DATA});
$res .= " $typedef->{NAME};\n\n";
return $res;
}
#####################################################################
# dump a typedef
sub DumpFunction($)
{
my($function) = shift;
my($first) = 1;
my($res);
$res .= DumpType($function->{RETURN_TYPE});
$res .= " $function->{NAME}(\n";
for my $d (@{$function->{ELEMENTS}}) {
unless ($first) { $res .= ",\n"; } $first = 0;
$res .= DumpElement($d);
}
$res .= "\n);\n\n";
return $res;
}
#####################################################################
# dump a module header
sub DumpInterfaceProperties($)
{
my($header) = shift;
my($data) = $header->{DATA};
my($first) = 1;
my($res);
$res .= "[\n";
foreach my $k (keys %{$data}) {
$first || ($res .= ",\n"); $first = 0;
$res .= "$k($data->{$k})";
}
$res .= "\n]\n";
return $res;
}
#####################################################################
# dump the interface definitions
sub DumpInterface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
my($res);
$res .= DumpInterfaceProperties($interface->{PROPERTIES});
$res .= "interface $interface->{NAME}\n{\n";
foreach my $d (@{$data}) {
($d->{TYPE} eq "TYPEDEF") &&
($res .= DumpTypedef($d));
($d->{TYPE} eq "FUNCTION") &&
($res .= DumpFunction($d));
}
$res .= "}\n";
return $res;
}
#####################################################################
# dump a parsed IDL structure back into an IDL file
sub Dump($)
{
my($idl) = shift;
my($res);
$res = "/* Dumped by pidl */\n\n";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") &&
($res .= DumpInterface($x));
}
return $res;
}
1;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,131 @@
##########################################
# Converts ODL stuctures to IDL structures
# (C) 2004-2005, 2008 Jelmer Vernooij <jelmer@samba.org>
package Parse::Pidl::ODL;
use Parse::Pidl qw(error);
use Parse::Pidl::IDL;
use Parse::Pidl::Util qw(has_property unmake_str);
use Parse::Pidl::Typelist qw(hasType getType);
use File::Basename;
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
sub FunctionAddObjArgs($)
{
my $e = shift;
unshift(@{$e->{ELEMENTS}}, {
'NAME' => 'ORPCthis',
'POINTERS' => 0,
'PROPERTIES' => { 'in' => '1' },
'TYPE' => 'ORPCTHIS',
'FILE' => $e->{FILE},
'LINE' => $e->{LINE}
});
unshift(@{$e->{ELEMENTS}}, {
'NAME' => 'ORPCthat',
'POINTERS' => 1,
'PROPERTIES' => { 'out' => '1', 'ref' => '1' },
'TYPE' => 'ORPCTHAT',
'FILE' => $e->{FILE},
'LINE' => $e->{LINE}
});
}
sub ReplaceInterfacePointers($)
{
my ($e) = @_;
foreach my $x (@{$e->{ELEMENTS}}) {
next unless (hasType($x->{TYPE}));
next unless ref(getType($x->{TYPE})->{DATA}) eq "HASH";
next unless getType($x->{TYPE})->{DATA}->{TYPE} eq "INTERFACE";
$x->{TYPE} = "MInterfacePointer";
}
}
# Add ORPC specific bits to an interface.
sub ODL2IDL
{
my ($odl, $basedir, $opt_incdirs) = (@_);
my $addedorpc = 0;
my $interfaces = {};
foreach my $x (@$odl) {
if ($x->{TYPE} eq "IMPORT") {
foreach my $idl_file (@{$x->{PATHS}}) {
$idl_file = unmake_str($idl_file);
my $idl_path = undef;
foreach ($basedir, @$opt_incdirs) {
if (-f "$_/$idl_file") {
$idl_path = "$_/$idl_file";
last;
}
}
unless ($idl_path) {
error($x, "Unable to open include file `$idl_file'");
next;
}
my $podl = Parse::Pidl::IDL::parse_file($idl_path, $opt_incdirs);
if (defined(@$podl)) {
require Parse::Pidl::Typelist;
my $basename = basename($idl_path, ".idl");
Parse::Pidl::Typelist::LoadIdl($podl, $basename);
my $pidl = ODL2IDL($podl, $basedir, $opt_incdirs);
foreach my $y (@$pidl) {
if ($y->{TYPE} eq "INTERFACE") {
$interfaces->{$y->{NAME}} = $y;
}
}
} else {
error($x, "Failed to parse $idl_path");
}
}
}
if ($x->{TYPE} eq "INTERFACE") {
$interfaces->{$x->{NAME}} = $x;
# Add [in] ORPCTHIS *this, [out] ORPCTHAT *that
# and replace interfacepointers with MInterfacePointer
# for 'object' interfaces
if (has_property($x, "object")) {
foreach my $e (@{$x->{DATA}}) {
($e->{TYPE} eq "FUNCTION") && FunctionAddObjArgs($e);
ReplaceInterfacePointers($e);
}
$addedorpc = 1;
}
if ($x->{BASE}) {
my $base = $interfaces->{$x->{BASE}};
unless (defined($base)) {
error($x, "Undefined base interface `$x->{BASE}'");
} else {
foreach my $fn (reverse @{$base->{DATA}}) {
next unless ($fn->{TYPE} eq "FUNCTION");
push (@{$x->{INHERITED_FUNCTIONS}}, $fn);
}
}
}
}
}
unshift (@$odl, {
TYPE => "IMPORT",
PATHS => [ "\"orpc.idl\"" ],
FILE => undef,
LINE => undef
}) if ($addedorpc);
return $odl;
}
1;

View File

@ -0,0 +1,418 @@
###################################################
# Samba3 client generator for IDL structures
# on top of Samba4 style NDR functions
# Copyright jelmer@samba.org 2005-2006
# Copyright gd@samba.org 2008
# released under the GNU GPL
package Parse::Pidl::Samba3::ClientNDR;
use Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(ParseFunction $res $res_hdr);
use strict;
use Parse::Pidl qw(fatal warning error);
use Parse::Pidl::Util qw(has_property ParseExpr);
use Parse::Pidl::NDR qw(ContainsPipe);
use Parse::Pidl::Typelist qw(mapTypeName);
use Parse::Pidl::Samba4 qw(DeclLong);
use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv);
use vars qw($VERSION);
$VERSION = '0.01';
sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
sub genpad($)
{
my ($s) = @_;
my $nt = int((length($s)+1)/8);
my $lt = ($nt*8)-1;
my $ns = (length($s)-$lt);
return "\t"x($nt)." "x($ns);
}
sub new($)
{
my ($class) = shift;
my $self = { res => "", res_hdr => "", tabs => "" };
bless($self, $class);
}
sub ElementDirection($)
{
my ($e) = @_;
return "[in,out]" if (has_property($e, "in") and has_property($e, "out"));
return "[in]" if (has_property($e, "in"));
return "[out]" if (has_property($e, "out"));
return "[in,out]";
}
sub HeaderProperties($$)
{
my($props,$ignores) = @_;
my $ret = "";
foreach my $d (keys %{$props}) {
next if (grep(/^$d$/, @$ignores));
if($props->{$d} ne "1") {
$ret.= "$d($props->{$d}),";
} else {
$ret.="$d,";
}
}
if ($ret) {
return "[" . substr($ret, 0, -1) . "]";
}
}
sub ParseInvalidResponse($$)
{
my ($self, $type) = @_;
if ($type eq "sync") {
$self->pidl("return NT_STATUS_INVALID_NETWORK_RESPONSE;");
} elsif ($type eq "async") {
$self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);");
$self->pidl("return;");
} else {
die("ParseInvalidResponse($type)");
}
}
sub ParseFunctionAsyncState($$$)
{
my ($self, $if, $fn) = @_;
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $done_fn = "rpccli_$fn->{NAME}_done";
$self->pidl("$state_str {");
$self->indent;
$self->pidl("TALLOC_CTX *out_mem_ctx;");
if (defined($fn->{RETURN_TYPE})) {
$self->pidl(mapTypeName($fn->{RETURN_TYPE}). " result;");
}
$self->deindent;
$self->pidl("};");
$self->pidl("");
$self->pidl("static void $done_fn(struct tevent_req *subreq);");
$self->pidl("");
}
sub ParseFunctionAsyncSend($$$)
{
my ($self, $if, $fn) = @_;
my $fn_args = "";
my $uif = uc($if);
my $ufn = "NDR_".uc($fn->{NAME});
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $done_fn = "rpccli_$fn->{NAME}_done";
my $out_mem_ctx = "rpccli_$fn->{NAME}_out_memory";
my $fn_str = "struct tevent_req *rpccli_$fn->{NAME}_send";
my $pad = genpad($fn_str);
$fn_args .= "TALLOC_CTX *mem_ctx";
$fn_args .= ",\n" . $pad . "struct tevent_context *ev";
$fn_args .= ",\n" . $pad . "struct rpc_pipe_client *cli";
foreach (@{$fn->{ELEMENTS}}) {
my $dir = ElementDirection($_);
my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
$fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req;");
$self->pidl("$state_str *state;");
$self->pidl("struct tevent_req *subreq;");
$self->pidl("");
$self->pidl("req = tevent_req_create(mem_ctx, &state,");
$self->pidl("\t\t\t$state_str);");
$self->pidl("if (req == NULL) {");
$self->indent;
$self->pidl("return NULL;");
$self->deindent;
$self->pidl("}");
$self->pidl("state->out_mem_ctx = NULL;");
$self->pidl("");
my $out_params = 0;
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/out/, @{$_->{DIRECTION}})) {
$out_params++;
}
}
if ($out_params > 0) {
$self->pidl("state->out_mem_ctx = talloc_named_const(state, 0,");
$self->pidl("\t\t \"$out_mem_ctx\");");
$self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
$fn_str = "subreq = dcerpc_$fn->{NAME}_send";
$pad = "\t" . genpad($fn_str);
$fn_args = "state,\n" . $pad . "ev,\n" . $pad . "cli->binding_handle";
foreach (@{$fn->{ELEMENTS}}) {
$fn_args .= ",\n" . $pad . "_". $_->{NAME};
}
$self->pidl("$fn_str($fn_args);");
$self->pidl("if (tevent_req_nomem(subreq, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
$self->pidl("return req;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunctionAsyncDone($$$)
{
my ($self, $if, $fn) = @_;
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $done_fn = "rpccli_$fn->{NAME}_done";
$self->pidl("static void $done_fn(struct tevent_req *subreq)");
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req = tevent_req_callback_data(");
$self->pidl("\tsubreq, struct tevent_req);");
$self->pidl("$state_str *state = tevent_req_data(");
$self->pidl("\treq, $state_str);");
$self->pidl("NTSTATUS status;");
$self->pidl("TALLOC_CTX *mem_ctx;");
$self->pidl("");
$self->pidl("if (state->out_mem_ctx) {");
$self->indent;
$self->pidl("mem_ctx = state->out_mem_ctx;");
$self->deindent;
$self->pidl("} else {");
$self->indent;
$self->pidl("mem_ctx = state;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
my $fn_str = "status = dcerpc_$fn->{NAME}_recv";
my $pad = "\t" . genpad($fn_str);
my $fn_args = "subreq,\n" . $pad . "mem_ctx";
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . "&state->result";
}
$self->pidl("$fn_str($fn_args);");
$self->pidl("TALLOC_FREE(subreq);");
$self->pidl("if (!NT_STATUS_IS_OK(status)) {");
$self->indent;
$self->pidl("tevent_req_nterror(req, status);");
$self->pidl("return;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("tevent_req_done(req);");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunctionAsyncRecv($$$)
{
my ($self, $if, $fn) = @_;
my $fn_args = "";
my $state_str = "struct rpccli_$fn->{NAME}_state";
my $fn_str = "NTSTATUS rpccli_$fn->{NAME}_recv";
my $pad = genpad($fn_str);
$fn_args .= "struct tevent_req *req,\n" . $pad . "TALLOC_CTX *mem_ctx";
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . "$fn->{RETURN_TYPE} *result";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
$self->pidl("$state_str *state = tevent_req_data(");
$self->pidl("\treq, $state_str);");
$self->pidl("NTSTATUS status;");
$self->pidl("");
$self->pidl("if (tevent_req_is_nterror(req, &status)) {");
$self->indent;
$self->pidl("tevent_req_received(req);");
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("/* Steal possible out parameters to the callers context */");
$self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
$self->pidl("");
if (defined($fn->{RETURN_TYPE})) {
$self->pidl("/* Return result */");
$self->pidl("*result = state->result;");
$self->pidl("");
}
$self->pidl("tevent_req_received(req);");
$self->pidl("return NT_STATUS_OK;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunctionSync($$$)
{
my ($self, $if, $fn) = @_;
my $fn_args = "";
my $uif = uc($if);
my $ufn = "NDR_".uc($fn->{NAME});
my $fn_str = "NTSTATUS rpccli_$fn->{NAME}";
my $pad = genpad($fn_str);
$fn_args .= "struct rpc_pipe_client *cli,\n" . $pad . "TALLOC_CTX *mem_ctx";
foreach (@{$fn->{ELEMENTS}}) {
my $dir = ElementDirection($_);
my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
$fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
}
if (defined($fn->{RETURN_TYPE}) && ($fn->{RETURN_TYPE} eq "WERROR")) {
$fn_args .= ",\n" . $pad . "WERROR *werror";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
if (defined($fn->{RETURN_TYPE})) {
$self->pidl(mapTypeName($fn->{RETURN_TYPE})." result;");
}
$self->pidl("NTSTATUS status;");
$self->pidl("");
$fn_str = "status = dcerpc_$fn->{NAME}";
$pad = "\t" . genpad($fn_str);
$fn_args = "cli->binding_handle,\n" . $pad . "mem_ctx";
foreach (@{$fn->{ELEMENTS}}) {
$fn_args .= ",\n" . $pad . "_". $_->{NAME};
}
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . "&result";
}
$self->pidl("$fn_str($fn_args);");
$self->pidl("if (!NT_STATUS_IS_OK(status)) {");
$self->indent;
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("/* Return result */");
if (not $fn->{RETURN_TYPE}) {
$self->pidl("return NT_STATUS_OK;");
} elsif ($fn->{RETURN_TYPE} eq "NTSTATUS") {
$self->pidl("return result;");
} elsif ($fn->{RETURN_TYPE} eq "WERROR") {
$self->pidl("if (werror) {");
$self->indent;
$self->pidl("*werror = result;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("return werror_to_ntstatus(result);");
} else {
warning($fn->{ORIGINAL}, "Unable to convert $fn->{RETURN_TYPE} to NTSTATUS");
$self->pidl("return NT_STATUS_OK;");
}
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction($$$)
{
my ($self, $if, $fn) = @_;
$self->ParseFunctionAsyncState($if, $fn);
$self->ParseFunctionAsyncSend($if, $fn);
$self->ParseFunctionAsyncDone($if, $fn);
$self->ParseFunctionAsyncRecv($if, $fn);
$self->ParseFunctionSync($if, $fn);
}
sub ParseInterface($$)
{
my ($self, $if) = @_;
my $uif = uc($if->{NAME});
$self->pidl_hdr("#ifndef __CLI_$uif\__");
$self->pidl_hdr("#define __CLI_$uif\__");
foreach my $fn (@{$if->{FUNCTIONS}}) {
next if has_property($fn, "noopnum");
next if has_property($fn, "todo");
my $skip = 0;
foreach my $e (@{$fn->{ELEMENTS}}) {
if (ContainsPipe($e, $e->{LEVELS}[0])) {
$skip = 1;
last;
}
}
next if $skip;
$self->ParseFunction($if->{NAME}, $fn);
}
$self->pidl_hdr("#endif /* __CLI_$uif\__ */");
}
sub Parse($$$$)
{
my($self,$ndr,$header,$c_header) = @_;
$self->pidl("/*");
$self->pidl(" * Unix SMB/CIFS implementation.");
$self->pidl(" * client auto-generated by pidl. DO NOT MODIFY!");
$self->pidl(" */");
$self->pidl("");
$self->pidl("#include \"includes.h\"");
$self->pidl("#include \"$header\"");
$self->pidl_hdr("#include \"$c_header\"");
$self->pidl("");
foreach (@$ndr) {
$self->ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
}
return ($self->{res}, $self->{res_hdr});
}
1;

View File

@ -0,0 +1,309 @@
###################################################
# Samba3 server generator for IDL structures
# on top of Samba4 style NDR functions
# Copyright jelmer@samba.org 2005-2006
# released under the GNU GPL
package Parse::Pidl::Samba3::ServerNDR;
use Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(DeclLevel);
use strict;
use Parse::Pidl qw(warning error fatal);
use Parse::Pidl::Typelist qw(mapTypeName scalar_is_reference);
use Parse::Pidl::Util qw(ParseExpr has_property is_constant);
use Parse::Pidl::NDR qw(GetNextLevel);
use Parse::Pidl::Samba4 qw(ElementStars DeclLong);
use Parse::Pidl::Samba4::Header qw(GenerateFunctionOutEnv);
use vars qw($VERSION);
$VERSION = '0.01';
my $res;
my $res_hdr;
my $tabs = "";
sub indent() { $tabs.="\t"; }
sub deindent() { $tabs = substr($tabs, 1); }
sub pidl($) { my ($txt) = @_; $res .= $txt?$tabs.(shift)."\n":"\n"; }
sub pidl_hdr($) { $res_hdr .= (shift)."\n"; }
sub fn_declare($) { my ($n) = @_; pidl $n; pidl_hdr "$n;"; }
sub DeclLevel($$)
{
my ($e, $l) = @_;
my $res = "";
if (has_property($e, "charset")) {
$res .= "const char";
} else {
$res .= mapTypeName($e->{TYPE});
}
my $stars = ElementStars($e, $l);
$res .= " ".$stars unless ($stars eq "");
return $res;
}
sub AllocOutVar($$$$$)
{
my ($e, $mem_ctx, $name, $env, $fail) = @_;
my $l = $e->{LEVELS}[0];
# we skip pointer to arrays
if ($l->{TYPE} eq "POINTER") {
my $nl = GetNextLevel($e, $l);
$l = $nl if ($nl->{TYPE} eq "ARRAY");
} elsif
# we don't support multi-dimentional arrays yet
($l->{TYPE} eq "ARRAY") {
my $nl = GetNextLevel($e, $l);
if ($nl->{TYPE} eq "ARRAY") {
fatal($e->{ORIGINAL},"multi-dimentional [out] arrays are not supported!");
}
} else {
# neither pointer nor array, no need to alloc something.
return;
}
if ($l->{TYPE} eq "ARRAY") {
unless(defined($l->{SIZE_IS})) {
error($e->{ORIGINAL}, "No size known for array `$e->{NAME}'");
pidl "#error No size known for array `$e->{NAME}'";
} else {
my $size = ParseExpr($l->{SIZE_IS}, $env, $e);
pidl "$name = talloc_zero_array($mem_ctx, " . DeclLevel($e, 1) . ", $size);";
}
} else {
pidl "$name = talloc_zero($mem_ctx, " . DeclLevel($e, 1) . ");";
}
pidl "if ($name == NULL) {";
$fail->();
pidl "}";
pidl "";
}
sub CallWithStruct($$$$)
{
my ($pipes_struct, $mem_ctx, $fn, $fail) = @_;
my $env = GenerateFunctionOutEnv($fn);
my $hasout = 0;
foreach (@{$fn->{ELEMENTS}}) {
if (grep(/out/, @{$_->{DIRECTION}})) { $hasout = 1; }
}
pidl "ZERO_STRUCT(r->out);" if ($hasout);
my $proto = "_$fn->{NAME}(struct pipes_struct *p, struct $fn->{NAME} *r";
my $ret = "_$fn->{NAME}($pipes_struct, r";
foreach (@{$fn->{ELEMENTS}}) {
my @dir = @{$_->{DIRECTION}};
if (grep(/in/, @dir) and grep(/out/, @dir)) {
pidl "r->out.$_->{NAME} = r->in.$_->{NAME};";
}
}
foreach (@{$fn->{ELEMENTS}}) {
my @dir = @{$_->{DIRECTION}};
if (grep(/in/, @dir) and grep(/out/, @dir)) {
# noop
} elsif (grep(/out/, @dir) and not
has_property($_, "represent_as")) {
AllocOutVar($_, $mem_ctx, "r->out.$_->{NAME}", $env, $fail);
}
}
$ret .= ")";
$proto .= ");";
if ($fn->{RETURN_TYPE}) {
$ret = "r->out.result = $ret";
$proto = "$fn->{RETURN_TYPE} $proto";
} else {
$proto = "void $proto";
}
pidl_hdr "$proto";
pidl "$ret;";
}
sub ParseFunction($$)
{
my ($if,$fn) = @_;
my $op = "NDR_".uc($fn->{NAME});
pidl "static bool api_$fn->{NAME}(struct pipes_struct *p)";
pidl "{";
indent;
pidl "const struct ndr_interface_call *call;";
pidl "struct ndr_pull *pull;";
pidl "struct ndr_push *push;";
pidl "enum ndr_err_code ndr_err;";
pidl "struct $fn->{NAME} *r;";
pidl "";
pidl "call = &ndr_table_$if->{NAME}.calls[$op];";
pidl "";
pidl "r = talloc(talloc_tos(), struct $fn->{NAME});";
pidl "if (r == NULL) {";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "pull = ndr_pull_init_blob(&p->in_data.data, r);";
pidl "if (pull == NULL) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "pull->flags |= LIBNDR_FLAG_REF_ALLOC;";
pidl "if (p->endian) {";
pidl "\tpull->flags |= LIBNDR_FLAG_BIGENDIAN;";
pidl "}";
pidl "ndr_err = call->ndr_pull(pull, NDR_IN, r);";
pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "if (DEBUGLEVEL >= 10) {";
pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r);";
pidl "}";
pidl "";
CallWithStruct("p", "r", $fn,
sub {
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
}
);
pidl "";
pidl "if (p->fault_state) {";
pidl "\ttalloc_free(r);";
pidl "\t/* Return true here, srv_pipe_hnd.c will take care */";
pidl "\treturn true;";
pidl "}";
pidl "";
pidl "if (DEBUGLEVEL >= 10) {";
pidl "\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r);";
pidl "}";
pidl "";
pidl "push = ndr_push_init_ctx(r);";
pidl "if (push == NULL) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "/*";
pidl " * carry over the pointer count to the reply in case we are";
pidl " * using full pointer. See NDR specification for full pointers";
pidl " */";
pidl "push->ptr_count = pull->ptr_count;";
pidl "";
pidl "ndr_err = call->ndr_push(push, NDR_OUT, r);";
pidl "if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {";
pidl "\ttalloc_free(r);";
pidl "\treturn false;";
pidl "}";
pidl "";
pidl "p->out_data.rdata = ndr_push_blob(push);";
pidl "talloc_steal(p->mem_ctx, p->out_data.rdata.data);";
pidl "";
pidl "talloc_free(r);";
pidl "";
pidl "return true;";
deindent;
pidl "}";
pidl "";
}
sub ParseInterface($)
{
my $if = shift;
my $uif = uc($if->{NAME});
pidl_hdr "#ifndef __SRV_$uif\__";
pidl_hdr "#define __SRV_$uif\__";
foreach (@{$if->{FUNCTIONS}}) {
next if ($_->{PROPERTIES}{noopnum});
ParseFunction($if, $_);
}
pidl "";
pidl "/* Tables */";
pidl "static struct api_struct api_$if->{NAME}_cmds[] = ";
pidl "{";
indent;
foreach (@{$if->{FUNCTIONS}}) {
next if ($_->{PROPERTIES}{noopnum});
pidl "{\"" . uc($_->{NAME}) . "\", NDR_" . uc($_->{NAME}) . ", api_$_->{NAME}},";
}
deindent;
pidl "};";
pidl "";
pidl_hdr "void $if->{NAME}_get_pipe_fns(struct api_struct **fns, int *n_fns);";
pidl "void $if->{NAME}_get_pipe_fns(struct api_struct **fns, int *n_fns)";
pidl "{";
indent;
pidl "*fns = api_$if->{NAME}_cmds;";
pidl "*n_fns = sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct);";
deindent;
pidl "}";
pidl "";
if (not has_property($if, "no_srv_register")) {
pidl_hdr "struct rpc_srv_callbacks;";
pidl_hdr "NTSTATUS rpc_$if->{NAME}_init(const struct rpc_srv_callbacks *rpc_srv_cb);";
pidl "NTSTATUS rpc_$if->{NAME}_init(const struct rpc_srv_callbacks *rpc_srv_cb)";
pidl "{";
pidl "\treturn rpc_srv_register(SMB_RPC_INTERFACE_VERSION, \"$if->{NAME}\", \"$if->{NAME}\", \&ndr_table_$if->{NAME}, api_$if->{NAME}_cmds, sizeof(api_$if->{NAME}_cmds) / sizeof(struct api_struct), rpc_srv_cb);";
pidl "}";
pidl "";
pidl_hdr "NTSTATUS rpc_$if->{NAME}_shutdown(void);";
pidl "NTSTATUS rpc_$if->{NAME}_shutdown(void)";
pidl "{";
pidl "\treturn rpc_srv_unregister(\&ndr_table_$if->{NAME});";
pidl "}";
}
pidl_hdr "#endif /* __SRV_$uif\__ */";
}
sub Parse($$$)
{
my($ndr,$header,$ndr_header) = @_;
$res = "";
$res_hdr = "";
pidl "/*";
pidl " * Unix SMB/CIFS implementation.";
pidl " * server auto-generated by pidl. DO NOT MODIFY!";
pidl " */";
pidl "";
pidl "#include \"includes.h\"";
pidl "#include \"ntdomain.h\"";
pidl "#include \"$header\"";
pidl_hdr "#include \"$ndr_header\"";
pidl "";
foreach (@$ndr) {
ParseInterface($_) if ($_->{TYPE} eq "INTERFACE");
}
return ($res, $res_hdr);
}
1;

View File

@ -0,0 +1,133 @@
###################################################
# Common Samba4 functions
# Copyright jelmer@samba.org 2006
# released under the GNU GPL
package Parse::Pidl::Samba4;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(is_intree choose_header NumStars ElementStars ArrayBrackets DeclLong ArrayDynamicallyAllocated);
use Parse::Pidl::Util qw(has_property is_constant);
use Parse::Pidl::NDR qw(GetNextLevel);
use Parse::Pidl::Typelist qw(mapTypeName scalar_is_reference);
use Parse::Pidl qw(fatal error);
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
# return true if we are using pidl within the samba source tree. This changes
# the names of include files, as some include files (such as ntstatus.h) have
# different paths when installed to the patch in the source tree
sub is_intree()
{
my $srcdir = $ENV{srcdir};
$srcdir = $srcdir ? "$srcdir/" : "";
return 1 if (-f "${srcdir}kdc/kdc.c");
return 1 if (-d "${srcdir}source4");
return 1 if (-f "${srcdir}include/smb.h");
return 0;
}
# Return an #include line depending on whether this build is an in-tree
# build or not.
sub choose_header($$)
{
my ($in,$out) = @_;
return "#include \"$in\"" if (is_intree());
return "#include <$out>";
}
sub ArrayDynamicallyAllocated($$)
{
my ($e, $l) = @_;
die("Not an array") unless ($l->{TYPE} eq "ARRAY");
return 0 if ($l->{IS_FIXED} and not has_property($e, "charset"));
return 1;
}
sub NumStars($;$)
{
my ($e, $d) = @_;
$d = 0 unless defined($d);
my $n = 0;
foreach my $l (@{$e->{LEVELS}}) {
next unless ($l->{TYPE} eq "POINTER");
my $nl = GetNextLevel($e, $l);
next if (defined($nl) and $nl->{TYPE} eq "ARRAY");
$n++;
}
if ($n >= 1) {
$n-- if (scalar_is_reference($e->{TYPE}));
}
foreach my $l (@{$e->{LEVELS}}) {
next unless ($l->{TYPE} eq "ARRAY");
next unless (ArrayDynamicallyAllocated($e, $l));
$n++;
}
error($e->{ORIGINAL}, "Too few pointers $n < $d") if ($n < $d);
$n -= $d;
return $n;
}
sub ElementStars($;$)
{
my ($e, $d) = @_;
my $res = "";
my $n = 0;
$n = NumStars($e, $d);
$res .= "*" foreach (1..$n);
return $res;
}
sub ArrayBrackets($)
{
my ($e) = @_;
my $res = "";
foreach my $l (@{$e->{LEVELS}}) {
next unless ($l->{TYPE} eq "ARRAY");
next if ArrayDynamicallyAllocated($e, $l);
$res .= "[$l->{SIZE_IS}]";
}
return $res;
}
sub DeclLong($;$)
{
my ($e, $p) = @_;
my $res = "";
$p = "" unless defined($p);
if (has_property($e, "represent_as")) {
$res .= mapTypeName($e->{PROPERTIES}->{represent_as})." ";
} else {
if (has_property($e, "charset")) {
$res .= "const char ";
} else {
$res .= mapTypeName($e->{TYPE})." ";
}
$res .= ElementStars($e);
}
$res .= $p.$e->{NAME};
$res .= ArrayBrackets($e);
return $res;
}
1;

View File

@ -0,0 +1,160 @@
# COM Header generation
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
package Parse::Pidl::Samba4::COM::Header;
use Parse::Pidl::Typelist qw(mapTypeName);
use Parse::Pidl::Util qw(has_property is_constant);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
sub GetArgumentProtoList($)
{
my $f = shift;
my $res = "";
foreach my $a (@{$f->{ELEMENTS}}) {
$res .= ", " . mapTypeName($a->{TYPE}) . " ";
my $l = $a->{POINTERS};
$l-- if (Parse::Pidl::Typelist::scalar_is_reference($a->{TYPE}));
foreach my $i (1..$l) {
$res .= "*";
}
if (defined $a->{ARRAY_LEN}[0] && !is_constant($a->{ARRAY_LEN}[0]) &&
!$a->{POINTERS}) {
$res .= "*";
}
$res .= $a->{NAME};
if (defined $a->{ARRAY_LEN}[0] && is_constant($a->{ARRAY_LEN}[0])) {
$res .= "[$a->{ARRAY_LEN}[0]]";
}
}
return $res;
}
sub GetArgumentList($)
{
my $f = shift;
my $res = "";
foreach (@{$f->{ELEMENTS}}) { $res .= ", $_->{NAME}"; }
return $res;
}
#####################################################################
# generate vtable structure for COM interface
sub HeaderVTable($)
{
my $interface = shift;
my $res;
$res .= "#define " . uc($interface->{NAME}) . "_METHODS \\\n";
if (defined($interface->{BASE})) {
$res .= "\t" . uc($interface->{BASE} . "_METHODS") . "\\\n";
}
my $data = $interface->{DATA};
foreach my $d (@{$data}) {
$res .= "\t" . mapTypeName($d->{RETURN_TYPE}) . " (*$d->{NAME}) (struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . GetArgumentProtoList($d) . ");\\\n" if ($d->{TYPE} eq "FUNCTION");
}
$res .= "\n";
$res .= "struct $interface->{NAME}_vtable {\n";
$res .= "\tstruct GUID iid;\n";
$res .= "\t" . uc($interface->{NAME}) . "_METHODS\n";
$res .= "};\n\n";
return $res;
}
sub ParseInterface($)
{
my $if = shift;
my $res;
$res .= "\n#ifndef _$if->{NAME}_\n";
$res .= "#define _$if->{NAME}_\n";
$res .="\n\n/* $if->{NAME} */\n";
$res .="#define COM_" . uc($if->{NAME}) . "_UUID $if->{PROPERTIES}->{uuid}\n\n";
$res .="struct $if->{NAME}_vtable;\n\n";
$res .="struct $if->{NAME} {
struct OBJREF obj;
struct com_context *ctx;
struct $if->{NAME}_vtable *vtable;
void *object_data;
};\n\n";
$res.=HeaderVTable($if);
foreach my $d (@{$if->{DATA}}) {
next if ($d->{TYPE} ne "FUNCTION");
$res .= "#define $if->{NAME}_$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . ") ";
$res .= "((interface)->vtable->$d->{NAME}(interface, mem_ctx" . GetArgumentList($d) . "))";
$res .="\n";
}
$res .= "#endif\n";
return $res;
}
sub ParseCoClass($)
{
my ($c) = @_;
my $res = "";
$res .= "#define CLSID_" . uc($c->{NAME}) . " $c->{PROPERTIES}->{uuid}\n";
if (has_property($c, "progid")) {
$res .= "#define PROGID_" . uc($c->{NAME}) . " $c->{PROPERTIES}->{progid}\n";
}
$res .= "\n";
return $res;
}
sub Parse($$)
{
my ($idl,$ndr_header) = @_;
my $res = "";
my $has_obj = 0;
$res .= "#include \"librpc/gen_ndr/orpc.h\"\n" .
"#include \"$ndr_header\"\n\n";
foreach (@{$idl})
{
if ($_->{TYPE} eq "INTERFACE" && has_property($_, "object")) {
$res .="struct $_->{NAME};\n";
$has_obj = 1;
}
}
foreach (@{$idl})
{
if ($_->{TYPE} eq "INTERFACE" && has_property($_, "object")) {
$res.=ParseInterface($_);
$has_obj = 1;
}
if ($_->{TYPE} eq "COCLASS") {
$res.=ParseCoClass($_);
$has_obj = 1;
}
}
return $res if ($has_obj);
return undef;
}
1;

View File

@ -0,0 +1,225 @@
###################################################
# DCOM parser for Samba
# Basically the glue between COM and DCE/RPC with NDR
# Copyright jelmer@samba.org 2003-2005
# released under the GNU GPL
package Parse::Pidl::Samba4::COM::Proxy;
use Parse::Pidl::Samba4::COM::Header;
use Parse::Pidl::Typelist qw(mapTypeName);
use Parse::Pidl::Util qw(has_property);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
my($res);
sub ParseVTable($$)
{
my ($interface, $name) = @_;
# Generate the vtable
$res .="\tstruct $interface->{NAME}_vtable $name = {";
if (defined($interface->{BASE})) {
$res .= "\n\t\t{},";
}
my $data = $interface->{DATA};
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") {
$res .= "\n\t\tdcom_proxy_$interface->{NAME}_$d->{NAME}";
$res .= ",";
}
}
$res .= "\n\t};\n\n";
}
sub ParseRegFunc($)
{
my $interface = shift;
$res .= "static NTSTATUS dcom_proxy_$interface->{NAME}_init(void)
{
struct $interface->{NAME}_vtable *proxy_vtable = talloc(talloc_autofree_context(), struct $interface->{NAME}_vtable);
";
if (defined($interface->{BASE})) {
$res.= "
struct GUID base_iid;
const void *base_vtable;
base_iid = ndr_table_$interface->{BASE}.syntax_id.uuid;
base_vtable = dcom_proxy_vtable_by_iid(&base_iid);
if (base_vtable == NULL) {
DEBUG(0, (\"No proxy registered for base interface '$interface->{BASE}'\\n\"));
return NT_STATUS_FOOBAR;
}
memcpy(&proxy_vtable, base_vtable, sizeof(struct $interface->{BASE}_vtable));
";
}
foreach my $x (@{$interface->{DATA}}) {
next unless ($x->{TYPE} eq "FUNCTION");
$res .= "\tproxy_vtable->$x->{NAME} = dcom_proxy_$interface->{NAME}_$x->{NAME};\n";
}
$res.= "
proxy_vtable->iid = ndr_table_$interface->{NAME}.syntax_id.uuid;
return dcom_register_proxy((struct IUnknown_vtable *)proxy_vtable);
}\n\n";
}
#####################################################################
# parse a function
sub ParseFunction($$)
{
my ($interface, $fn) = @_;
my $name = $fn->{NAME};
my $uname = uc $name;
my $tn = mapTypeName($fn->{RETURN_TYPE});
$res.="
static $tn dcom_proxy_$interface->{NAME}_$name(struct $interface->{NAME} *d, TALLOC_CTX *mem_ctx" . Parse::Pidl::Samba4::COM::Header::GetArgumentProtoList($fn) . ")
{
struct dcerpc_pipe *p;
NTSTATUS status = dcom_get_pipe(d, &p);
struct $name r;
struct rpc_request *req;
if (NT_STATUS_IS_ERR(status)) {
return status;
}
ZERO_STRUCT(r.in.ORPCthis);
r.in.ORPCthis.version.MajorVersion = COM_MAJOR_VERSION;
r.in.ORPCthis.version.MinorVersion = COM_MINOR_VERSION;
";
# Put arguments into r
foreach my $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "in"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
$res .="\tNDR_CHECK(dcom_OBJREF_from_IUnknown(mem_ctx, &r.in.$a->{NAME}.obj, $a->{NAME}));\n";
} else {
$res .= "\tr.in.$a->{NAME} = $a->{NAME};\n";
}
}
$res .="
if (p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
NDR_PRINT_IN_DEBUG($name, &r);
}
status = dcerpc_ndr_request(p, &d->ipid, &ndr_table_$interface->{NAME}, NDR_$uname, mem_ctx, &r);
if (NT_STATUS_IS_OK(status) && (p->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
NDR_PRINT_OUT_DEBUG($name, r);
}
";
# Put r info back into arguments
foreach my $a (@{$fn->{ELEMENTS}}) {
next unless (has_property($a, "out"));
if (Parse::Pidl::Typelist::typeIs($a->{TYPE}, "INTERFACE")) {
$res .="\tNDR_CHECK(dcom_IUnknown_from_OBJREF(d->ctx, &$a->{NAME}, r.out.$a->{NAME}.obj));\n";
} else {
$res .= "\t*$a->{NAME} = r.out.$a->{NAME};\n";
}
}
if ($fn->{RETURN_TYPE} eq "NTSTATUS") {
$res .= "\tif (NT_STATUS_IS_OK(status)) status = r.out.result;\n";
}
$res .=
"
return r.out.result;
}\n\n";
}
#####################################################################
# parse the interface definitions
sub ParseInterface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
$res = "/* DCOM proxy for $interface->{NAME} generated by pidl */\n\n";
foreach my $d (@{$data}) {
($d->{TYPE} eq "FUNCTION") &&
ParseFunction($interface, $d);
}
ParseRegFunc($interface);
}
sub RegistrationFunction($$)
{
my $idl = shift;
my $basename = shift;
my $res = "\n\nNTSTATUS dcom_$basename\_init(void)\n";
$res .= "{\n";
$res .="\tNTSTATUS status = NT_STATUS_OK;\n";
foreach my $interface (@{$idl}) {
next if $interface->{TYPE} ne "INTERFACE";
next if not has_property($interface, "object");
my $data = $interface->{DATA};
my $count = 0;
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") { $count++; }
}
next if ($count == 0);
$res .= "\tstatus = dcom_$interface->{NAME}_init();\n";
$res .= "\tif (NT_STATUS_IS_ERR(status)) {\n";
$res .= "\t\treturn status;\n";
$res .= "\t}\n\n";
}
$res .= "\treturn status;\n";
$res .= "}\n\n";
return $res;
}
sub Parse($$)
{
my ($pidl,$comh_filename) = @_;
my $res = "";
my $has_obj = 0;
$res .= "#include \"includes.h\"\n" .
"#include \"lib/com/dcom/dcom.h\"\n" .
"#include \"$comh_filename\"\n" .
"#include \"librpc/rpc/dcerpc.h\"\n";
foreach (@{$pidl}) {
next if ($_->{TYPE} ne "INTERFACE");
next if has_property($_, "local");
next unless has_property($_, "object");
$res .= ParseInterface($_);
$has_obj = 1;
}
return $res if ($has_obj);
return undef;
}
1;

View File

@ -0,0 +1,327 @@
###################################################
# DCOM stub boilerplate generator
# Copyright jelmer@samba.org 2004-2005
# Copyright tridge@samba.org 2003
# Copyright metze@samba.org 2004
# released under the GNU GPL
package Parse::Pidl::Samba4::COM::Stub;
use Parse::Pidl::Util qw(has_property);
use strict;
use vars qw($VERSION);
$VERSION = '0.01';
my($res);
sub pidl($)
{
$res .= shift;
}
#####################################################
# generate the switch statement for function dispatch
sub gen_dispatch_switch($)
{
my $data = shift;
my $count = 0;
foreach my $d (@{$data}) {
next if ($d->{TYPE} ne "FUNCTION");
pidl "\tcase $count: {\n";
if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
pidl "\t\tNTSTATUS result;\n";
}
pidl "\t\tstruct $d->{NAME} *r2 = r;\n";
pidl "\t\tif (DEBUGLEVEL > 10) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_IN, r2);\n";
pidl "\t\t}\n";
if ($d->{RETURN_TYPE} && $d->{RETURN_TYPE} ne "void") {
pidl "\t\tresult = vtable->$d->{NAME}(iface, mem_ctx, r2);\n";
} else {
pidl "\t\tvtable->$d->{NAME}(iface, mem_ctx, r2);\n";
}
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $d->{NAME} will reply async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
$count++;
}
}
#####################################################
# generate the switch statement for function reply
sub gen_reply_switch($)
{
my $data = shift;
my $count = 0;
foreach my $d (@{$data}) {
next if ($d->{TYPE} ne "FUNCTION");
pidl "\tcase $count: {\n";
pidl "\t\tstruct $d->{NAME} *r2 = r;\n";
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $d->{NAME} replied async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tif (DEBUGLEVEL > 10 && dce_call->fault_code == 0) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($d->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n";
pidl "\t\t}\n";
pidl "\t\tif (dce_call->fault_code != 0) {\n";
pidl "\t\t\tDEBUG(2,(\"dcerpc_fault %s in $d->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code)));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
$count++;
}
}
#####################################################################
# produce boilerplate code for a interface
sub Boilerplate_Iface($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
my $name = $interface->{NAME};
my $uname = uc $name;
my $uuid = Parse::Pidl::Util::make_str($interface->{PROPERTIES}->{uuid});
my $if_version = $interface->{PROPERTIES}->{version};
pidl "
static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
{
#ifdef DCESRV_INTERFACE_$uname\_BIND
return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface);
#else
return NT_STATUS_OK;
#endif
}
static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
{
#ifdef DCESRV_INTERFACE_$uname\_UNBIND
DCESRV_INTERFACE_$uname\_UNBIND(context, iface);
#else
return;
#endif
}
static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
{
NTSTATUS status;
uint16_t opnum = dce_call->pkt.u.request.opnum;
dce_call->fault_code = 0;
if (opnum >= dcerpc_table_$name.num_calls) {
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
return NT_STATUS_NET_WRITE_FAULT;
}
*r = talloc_size(mem_ctx, dcerpc_table_$name.calls[opnum].struct_size);
NT_STATUS_HAVE_NO_MEMORY(*r);
/* unravel the NDR for the packet */
status = dcerpc_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);
if (!NT_STATUS_IS_OK(status)) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
struct GUID ipid = dce_call->pkt.u.request.object.object;
struct dcom_interface_p *iface = dcom_get_local_iface_p(&ipid);
const struct dcom_$name\_vtable *vtable = iface->vtable;
switch (opnum) {
";
gen_dispatch_switch($data);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
switch (opnum) {
";
gen_reply_switch($data);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(&dcerpc_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
{
NTSTATUS status;
uint16_t opnum = dce_call->pkt.u.request.opnum;
status = dcerpc_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NT_STATUS_IS_OK(status)) {
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static const struct dcesrv_interface $name\_interface = {
.name = \"$name\",
.uuid = $uuid,
.if_version = $if_version,
.bind = $name\__op_bind,
.unbind = $name\__op_unbind,
.ndr_pull = $name\__op_ndr_pull,
.dispatch = $name\__op_dispatch,
.reply = $name\__op_reply,
.ndr_push = $name\__op_ndr_push
};
";
}
#####################################################################
# produce boilerplate code for an endpoint server
sub Boilerplate_Ep_Server($)
{
my($interface) = shift;
my $name = $interface->{NAME};
my $uname = uc $name;
pidl "
static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
int i;
for (i=0;i<dcerpc_table_$name.endpoints->count;i++) {
NTSTATUS ret;
const char *name = dcerpc_table_$name.endpoints->names[i];
ret = dcesrv_interface_register(dce_ctx, name, &$name\_interface, NULL);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
return ret;
}
}
return NT_STATUS_OK;
}
static BOOL $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const char *uuid, uint32_t if_version)
{
if (dcerpc_table_$name.if_version == if_version &&
strcmp(dcerpc_table_$name.uuid, uuid)==0) {
memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
return True;
}
return False;
}
static BOOL $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
{
if (strcmp(dcerpc_table_$name.name, name)==0) {
memcpy(iface,&dcerpc_table_$name, sizeof(*iface));
return True;
}
return False;
}
NTSTATUS dcerpc_server_$name\_init(void)
{
NTSTATUS ret;
struct dcesrv_endpoint_server ep_server;
/* fill in our name */
ep_server.name = \"$name\";
/* fill in all the operations */
ep_server.init_server = $name\__op_init_server;
ep_server.interface_by_uuid = $name\__op_interface_by_uuid;
ep_server.interface_by_name = $name\__op_interface_by_name;
/* register ourselves with the DCERPC subsystem. */
ret = dcerpc_register_ep_server(&ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
return ret;
}
return ret;
}
";
}
#####################################################################
# dcom interface stub from a parsed IDL structure
sub ParseInterface($)
{
my($interface) = shift;
return "" if has_property($interface, "local");
my($data) = $interface->{DATA};
my $count = 0;
$res = "";
if (!defined $interface->{PROPERTIES}->{uuid}) {
return $res;
}
if (!defined $interface->{PROPERTIES}->{version}) {
$interface->{PROPERTIES}->{version} = "0.0";
}
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") { $count++; }
}
if ($count == 0) {
return $res;
}
$res = "/* dcom interface stub generated by pidl */\n\n";
Boilerplate_Iface($interface);
Boilerplate_Ep_Server($interface);
return $res;
}
1;

View File

@ -0,0 +1,537 @@
###################################################
# create C header files for an IDL structure
# Copyright tridge@samba.org 2000
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Samba4::Header;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(GenerateFunctionInEnv GenerateFunctionOutEnv EnvSubstituteValue GenerateStructEnv);
use strict;
use Parse::Pidl qw(fatal);
use Parse::Pidl::Typelist qw(mapTypeName scalar_is_reference);
use Parse::Pidl::Util qw(has_property is_constant unmake_str ParseExpr);
use Parse::Pidl::Samba4 qw(is_intree ElementStars ArrayBrackets choose_header);
use vars qw($VERSION);
$VERSION = '0.01';
my($res);
my($tab_depth);
sub pidl($) { $res .= shift; }
sub tabs()
{
my $res = "";
$res .="\t" foreach (1..$tab_depth);
return $res;
}
#####################################################################
# parse a properties list
sub HeaderProperties($$)
{
my($props,$ignores) = @_;
my $ret = "";
foreach my $d (keys %{$props}) {
next if (grep(/^$d$/, @$ignores));
if($props->{$d} ne "1") {
$ret.= "$d($props->{$d}),";
} else {
$ret.="$d,";
}
}
if ($ret) {
pidl "/* [" . substr($ret, 0, -1) . "] */";
}
}
#####################################################################
# parse a structure element
sub HeaderElement($)
{
my($element) = shift;
pidl tabs();
if (has_property($element, "represent_as")) {
pidl mapTypeName($element->{PROPERTIES}->{represent_as})." ";
} else {
if (ref($element->{TYPE}) eq "HASH") {
HeaderType($element, $element->{TYPE}, $element->{TYPE}->{NAME});
} else {
HeaderType($element, $element->{TYPE}, "");
}
pidl " ".ElementStars($element);
}
pidl $element->{NAME};
pidl ArrayBrackets($element);
pidl ";";
if (defined $element->{PROPERTIES}) {
HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
}
pidl "\n";
}
#####################################################################
# parse a struct
sub HeaderStruct($$;$)
{
my($struct,$name,$tail) = @_;
pidl "struct $name";
pidl $tail if defined($tail) and not defined($struct->{ELEMENTS});
return if (not defined($struct->{ELEMENTS}));
pidl " {\n";
$tab_depth++;
my $el_count=0;
foreach (@{$struct->{ELEMENTS}}) {
HeaderElement($_);
$el_count++;
}
if ($el_count == 0) {
# some compilers can't handle empty structures
pidl tabs()."char _empty_;\n";
}
$tab_depth--;
pidl tabs()."}";
if (defined $struct->{PROPERTIES}) {
HeaderProperties($struct->{PROPERTIES}, []);
}
pidl $tail if defined($tail);
}
#####################################################################
# parse a enum
sub HeaderEnum($$;$)
{
my($enum,$name,$tail) = @_;
my $first = 1;
pidl "enum $name";
if (defined($enum->{ELEMENTS})) {
pidl "\n#ifndef USE_UINT_ENUMS\n";
pidl " {\n";
$tab_depth++;
foreach my $e (@{$enum->{ELEMENTS}}) {
my @enum_els = ();
unless ($first) { pidl ",\n"; }
$first = 0;
pidl tabs();
@enum_els = split(/=/, $e);
if (@enum_els == 2) {
pidl $enum_els[0];
pidl "=(int)";
pidl "(";
pidl $enum_els[1];
pidl ")";
} else {
pidl $e;
}
}
pidl "\n";
$tab_depth--;
pidl "}";
pidl "\n";
pidl "#else\n";
my $count = 0;
my $with_val = 0;
my $without_val = 0;
pidl " { __do_not_use_enum_$name=0x7FFFFFFF}\n";
foreach my $e (@{$enum->{ELEMENTS}}) {
my $t = "$e";
my $name;
my $value;
if ($t =~ /(.*)=(.*)/) {
$name = $1;
$value = $2;
$with_val = 1;
fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
unless ($without_val == 0);
} else {
$name = $t;
$value = $count++;
$without_val = 1;
fatal($e->{ORIGINAL}, "you can't mix enum member with values and without values!")
unless ($with_val == 0);
}
pidl "#define $name ( $value )\n";
}
pidl "#endif\n";
}
pidl $tail if defined($tail);
}
#####################################################################
# parse a bitmap
sub HeaderBitmap($$)
{
my($bitmap,$name) = @_;
return unless defined($bitmap->{ELEMENTS});
pidl "/* bitmap $name */\n";
pidl "#define $_\n" foreach (@{$bitmap->{ELEMENTS}});
pidl "\n";
}
#####################################################################
# parse a union
sub HeaderUnion($$;$)
{
my($union,$name,$tail) = @_;
my %done = ();
pidl "union $name";
pidl $tail if defined($tail) and not defined($union->{ELEMENTS});
return if (not defined($union->{ELEMENTS}));
pidl " {\n";
$tab_depth++;
my $needed = 0;
foreach my $e (@{$union->{ELEMENTS}}) {
if ($e->{TYPE} ne "EMPTY") {
if (! defined $done{$e->{NAME}}) {
HeaderElement($e);
}
$done{$e->{NAME}} = 1;
$needed++;
}
}
if (!$needed) {
# sigh - some compilers don't like empty structures
pidl tabs()."int _dummy_element;\n";
}
$tab_depth--;
pidl "}";
if (defined $union->{PROPERTIES}) {
HeaderProperties($union->{PROPERTIES}, []);
}
pidl $tail if defined($tail);
}
#####################################################################
# parse a pipe
sub HeaderPipe($$;$)
{
my($pipe,$name,$tail) = @_;
my $struct = $pipe->{DATA};
my $e = $struct->{ELEMENTS}[1];
pidl "struct $name;\n";
pidl "struct $struct->{NAME} {\n";
$tab_depth++;
pidl tabs()."uint32_t count;\n";
pidl tabs().mapTypeName($e->{TYPE})." *array;\n";
$tab_depth--;
pidl "}";
if (defined $struct->{PROPERTIES}) {
HeaderProperties($struct->{PROPERTIES}, []);
}
pidl $tail if defined($tail);
}
#####################################################################
# parse a type
sub HeaderType($$$;$)
{
my($e,$data,$name,$tail) = @_;
if (ref($data) eq "HASH") {
($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name, $tail);
($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name, $tail);
($data->{TYPE} eq "UNION") && HeaderUnion($data, $name, $tail);
($data->{TYPE} eq "PIPE") && HeaderPipe($data, $name, $tail);
return;
}
if (has_property($e, "charset")) {
pidl "const char";
} else {
pidl mapTypeName($e->{TYPE});
}
pidl $tail if defined($tail);
}
#####################################################################
# parse a typedef
sub HeaderTypedef($;$)
{
my($typedef,$tail) = @_;
# Don't print empty "enum foo;", since some compilers don't like it.
return if ($typedef->{DATA}->{TYPE} eq "ENUM" and not defined($typedef->{DATA}->{ELEMENTS}));
HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME}, $tail) if defined ($typedef->{DATA});
}
#####################################################################
# parse a const
sub HeaderConst($)
{
my($const) = shift;
if (!defined($const->{ARRAY_LEN}[0])) {
pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
} else {
pidl "#define $const->{NAME}\t $const->{VALUE}\n";
}
}
sub ElementDirection($)
{
my ($e) = @_;
return "inout" if (has_property($e, "in") and has_property($e, "out"));
return "in" if (has_property($e, "in"));
return "out" if (has_property($e, "out"));
return "inout";
}
#####################################################################
# parse a function
sub HeaderFunctionInOut($$)
{
my($fn,$prop) = @_;
return unless defined($fn->{ELEMENTS});
foreach my $e (@{$fn->{ELEMENTS}}) {
HeaderElement($e) if (ElementDirection($e) eq $prop);
}
}
#####################################################################
# determine if we need an "in" or "out" section
sub HeaderFunctionInOut_needed($$)
{
my($fn,$prop) = @_;
return 1 if ($prop eq "out" && defined($fn->{RETURN_TYPE}));
return undef unless defined($fn->{ELEMENTS});
foreach my $e (@{$fn->{ELEMENTS}}) {
return 1 if (ElementDirection($e) eq $prop);
}
return undef;
}
my %headerstructs;
#####################################################################
# parse a function
sub HeaderFunction($)
{
my($fn) = shift;
return if ($headerstructs{$fn->{NAME}});
$headerstructs{$fn->{NAME}} = 1;
pidl "\nstruct $fn->{NAME} {\n";
$tab_depth++;
my $needed = 0;
if (HeaderFunctionInOut_needed($fn, "in") or
HeaderFunctionInOut_needed($fn, "inout")) {
pidl tabs()."struct {\n";
$tab_depth++;
HeaderFunctionInOut($fn, "in");
HeaderFunctionInOut($fn, "inout");
$tab_depth--;
pidl tabs()."} in;\n\n";
$needed++;
}
if (HeaderFunctionInOut_needed($fn, "out") or
HeaderFunctionInOut_needed($fn, "inout")) {
pidl tabs()."struct {\n";
$tab_depth++;
HeaderFunctionInOut($fn, "out");
HeaderFunctionInOut($fn, "inout");
if (defined($fn->{RETURN_TYPE})) {
pidl tabs().mapTypeName($fn->{RETURN_TYPE}) . " result;\n";
}
$tab_depth--;
pidl tabs()."} out;\n\n";
$needed++;
}
if (!$needed) {
# sigh - some compilers don't like empty structures
pidl tabs()."int _dummy_element;\n";
}
$tab_depth--;
pidl "};\n\n";
}
sub HeaderImport
{
my @imports = @_;
foreach my $import (@imports) {
$import = unmake_str($import);
$import =~ s/\.idl$//;
pidl choose_header("librpc/gen_ndr/$import\.h", "gen_ndr/$import.h") . "\n";
}
}
sub HeaderInclude
{
my @includes = @_;
foreach (@includes) {
pidl "#include $_\n";
}
}
#####################################################################
# parse the interface definitions
sub HeaderInterface($)
{
my($interface) = shift;
pidl "#ifndef _HEADER_$interface->{NAME}\n";
pidl "#define _HEADER_$interface->{NAME}\n\n";
foreach my $c (@{$interface->{CONSTS}}) {
HeaderConst($c);
}
foreach my $t (@{$interface->{TYPES}}) {
HeaderTypedef($t, ";\n\n") if ($t->{TYPE} eq "TYPEDEF");
HeaderStruct($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "STRUCT");
HeaderUnion($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "UNION");
HeaderEnum($t, $t->{NAME}, ";\n\n") if ($t->{TYPE} eq "ENUM");
HeaderBitmap($t, $t->{NAME}) if ($t->{TYPE} eq "BITMAP");
HeaderPipe($t, $t->{NAME}, "\n\n") if ($t->{TYPE} eq "PIPE");
}
foreach my $fn (@{$interface->{FUNCTIONS}}) {
HeaderFunction($fn);
}
pidl "#endif /* _HEADER_$interface->{NAME} */\n";
}
sub HeaderQuote($)
{
my($quote) = shift;
pidl unmake_str($quote->{DATA}) . "\n";
}
#####################################################################
# parse a parsed IDL into a C header
sub Parse($)
{
my($ndr) = shift;
$tab_depth = 0;
$res = "";
%headerstructs = ();
pidl "/* header auto-generated by pidl */\n\n";
my $ifacename = "";
# work out a unique interface name
foreach (@{$ndr}) {
if ($_->{TYPE} eq "INTERFACE") {
$ifacename = $_->{NAME};
last;
}
}
pidl "#ifndef _PIDL_HEADER_$ifacename\n";
pidl "#define _PIDL_HEADER_$ifacename\n\n";
if (!is_intree()) {
pidl "#include <util/data_blob.h>\n";
}
pidl "#include <stdint.h>\n";
pidl "\n";
# FIXME: Include this only if NTSTATUS was actually used
pidl choose_header("libcli/util/ntstatus.h", "core/ntstatus.h") . "\n";
pidl "\n";
foreach (@{$ndr}) {
($_->{TYPE} eq "CPP_QUOTE") && HeaderQuote($_);
($_->{TYPE} eq "INTERFACE") && HeaderInterface($_);
($_->{TYPE} eq "IMPORT") && HeaderImport(@{$_->{PATHS}});
($_->{TYPE} eq "INCLUDE") && HeaderInclude(@{$_->{PATHS}});
}
pidl "#endif /* _PIDL_HEADER_$ifacename */\n";
return $res;
}
sub GenerateStructEnv($$)
{
my ($x, $v) = @_;
my %env;
foreach my $e (@{$x->{ELEMENTS}}) {
$env{$e->{NAME}} = "$v->$e->{NAME}";
}
$env{"this"} = $v;
return \%env;
}
sub EnvSubstituteValue($$)
{
my ($env,$s) = @_;
# Substitute the value() values in the env
foreach my $e (@{$s->{ELEMENTS}}) {
next unless (defined(my $v = has_property($e, "value")));
$env->{$e->{NAME}} = ParseExpr($v, $env, $e);
}
return $env;
}
sub GenerateFunctionInEnv($;$)
{
my ($fn, $base) = @_;
my %env;
$base = "r->" unless defined($base);
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep (/in/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = $base."in.$e->{NAME}";
}
}
return \%env;
}
sub GenerateFunctionOutEnv($;$)
{
my ($fn, $base) = @_;
my %env;
$base = "r->" unless defined($base);
foreach my $e (@{$fn->{ELEMENTS}}) {
if (grep (/out/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = $base."out.$e->{NAME}";
} elsif (grep (/in/, @{$e->{DIRECTION}})) {
$env{$e->{NAME}} = $base."in.$e->{NAME}";
}
}
return \%env;
}
1;

View File

@ -0,0 +1,875 @@
###################################################
# client calls generator
# Copyright tridge@samba.org 2003
# Copyright jelmer@samba.org 2005-2006
# released under the GNU GPL
package Parse::Pidl::Samba4::NDR::Client;
use Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(Parse);
use Parse::Pidl qw(fatal warning error);
use Parse::Pidl::Util qw(has_property ParseExpr);
use Parse::Pidl::NDR qw(ContainsPipe);
use Parse::Pidl::Typelist qw(mapTypeName);
use Parse::Pidl::Samba4 qw(choose_header is_intree DeclLong);
use Parse::Pidl::Samba4::Header qw(GenerateFunctionInEnv GenerateFunctionOutEnv);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
sub indent($) { my ($self) = @_; $self->{tabs}.="\t"; }
sub deindent($) { my ($self) = @_; $self->{tabs} = substr($self->{tabs}, 1); }
sub pidl($$) { my ($self,$txt) = @_; $self->{res} .= $txt ? "$self->{tabs}$txt\n" : "\n"; }
sub pidl_hdr($$) { my ($self, $txt) = @_; $self->{res_hdr} .= "$txt\n"; }
sub pidl_both($$) { my ($self, $txt) = @_; $self->{hdr} .= "$txt\n"; $self->{res_hdr} .= "$txt\n"; }
sub fn_declare($$) { my ($self,$n) = @_; $self->pidl($n); $self->pidl_hdr("$n;"); }
sub genpad($)
{
my ($s) = @_;
my $nt = int((length($s)+1)/8);
my $lt = ($nt*8)-1;
my $ns = (length($s)-$lt);
return "\t"x($nt)." "x($ns);
}
sub new($)
{
my ($class) = shift;
my $self = { res => "", res_hdr => "", tabs => "" };
bless($self, $class);
}
sub ParseFunctionHasPipes($$)
{
my ($self, $fn) = @_;
foreach my $e (@{$fn->{ELEMENTS}}) {
return 1 if ContainsPipe($e, $e->{LEVELS}[0]);
}
return 0;
}
sub ParseFunction_r_State($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $uname = uc $name;
$self->pidl("struct dcerpc_$name\_r_state {");
$self->indent;
$self->pidl("TALLOC_CTX *out_mem_ctx;");
$self->deindent;
$self->pidl("};");
$self->pidl("");
$self->pidl("static void dcerpc_$name\_r_done(struct tevent_req *subreq);");
$self->pidl("");
}
sub ParseFunction_r_Send($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $uname = uc $name;
my $proto = "struct tevent_req *dcerpc_$name\_r_send(TALLOC_CTX *mem_ctx,\n";
$proto .= "\tstruct tevent_context *ev,\n",
$proto .= "\tstruct dcerpc_binding_handle *h,\n",
$proto .= "\tstruct $name *r)";
$self->fn_declare($proto);
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req;");
$self->pidl("struct dcerpc_$name\_r_state *state;");
$self->pidl("struct tevent_req *subreq;");
$self->pidl("");
$self->pidl("req = tevent_req_create(mem_ctx, &state,");
$self->pidl("\t\t\tstruct dcerpc_$name\_r_state);");
$self->pidl("if (req == NULL) {");
$self->indent;
$self->pidl("return NULL;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
my $out_params = 0;
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless grep(/out/, @{$e->{DIRECTION}});
next if ContainsPipe($e, $e->{LEVELS}[0]);
$out_params++;
}
my $submem;
if ($out_params > 0) {
$self->pidl("state->out_mem_ctx = talloc_new(state);");
$self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$submem = "state->out_mem_ctx";
} else {
$self->pidl("state->out_mem_ctx = NULL;");
$submem = "state";
}
$self->pidl("");
$self->pidl("subreq = dcerpc_binding_handle_call_send(state, ev, h,");
$self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
$self->pidl("\t\tNDR_$uname, $submem, r);");
$self->pidl("if (tevent_req_nomem(subreq, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$self->pidl("tevent_req_set_callback(subreq, dcerpc_$name\_r_done, req);");
$self->pidl("");
$self->pidl("return req;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction_r_Done($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $uname = uc $name;
my $proto = "static void dcerpc_$name\_r_done(struct tevent_req *subreq)";
$self->pidl("$proto");
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req =");
$self->pidl("\ttevent_req_callback_data(subreq,");
$self->pidl("\tstruct tevent_req);");
$self->pidl("NTSTATUS status;");
$self->pidl("");
$self->pidl("status = dcerpc_binding_handle_call_recv(subreq);");
$self->pidl("if (!NT_STATUS_IS_OK(status)) {");
$self->indent;
$self->pidl("tevent_req_nterror(req, status);");
$self->pidl("return;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("tevent_req_done(req);");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction_r_Recv($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $uname = uc $name;
my $proto = "NTSTATUS dcerpc_$name\_r_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)";
$self->fn_declare($proto);
$self->pidl("{");
$self->indent;
$self->pidl("struct dcerpc_$name\_r_state *state =");
$self->pidl("\ttevent_req_data(req,");
$self->pidl("\tstruct dcerpc_$name\_r_state);");
$self->pidl("NTSTATUS status;");
$self->pidl("");
$self->pidl("if (tevent_req_is_nterror(req, &status)) {");
$self->indent;
$self->pidl("tevent_req_received(req);");
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
$self->pidl("");
$self->pidl("tevent_req_received(req);");
$self->pidl("return NT_STATUS_OK;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction_r_Sync($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $uname = uc $name;
if ($self->ParseFunctionHasPipes($fn)) {
$self->pidl_both("/*");
$self->pidl_both(" * The following function is skipped because");
$self->pidl_both(" * it uses pipes:");
$self->pidl_both(" *");
$self->pidl_both(" * dcerpc_$name\_r()");
$self->pidl_both(" */");
$self->pidl_both("");
return;
}
my $proto = "NTSTATUS dcerpc_$name\_r(struct dcerpc_binding_handle *h, TALLOC_CTX *mem_ctx, struct $name *r)";
$self->fn_declare($proto);
$self->pidl("{");
$self->indent;
$self->pidl("NTSTATUS status;");
$self->pidl("");
$self->pidl("status = dcerpc_binding_handle_call(h,");
$self->pidl("\t\tNULL, &ndr_table_$if->{NAME},");
$self->pidl("\t\tNDR_$uname, mem_ctx, r);");
$self->pidl("");
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ElementDirection($)
{
my ($e) = @_;
return "[in,out]" if (has_property($e, "in") and has_property($e, "out"));
return "[in]" if (has_property($e, "in"));
return "[out]" if (has_property($e, "out"));
return "[in,out]";
}
sub HeaderProperties($$)
{
my($props,$ignores) = @_;
my $ret = "";
foreach my $d (keys %{$props}) {
next if (grep(/^$d$/, @$ignores));
if($props->{$d} ne "1") {
$ret.= "$d($props->{$d}),";
} else {
$ret.="$d,";
}
}
if ($ret) {
return "[" . substr($ret, 0, -1) . "]";
}
}
sub ParseCopyArgument($$$$$)
{
my ($self, $fn, $e, $r, $i) = @_;
my $l = $e->{LEVELS}[0];
if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED} == 1) {
$self->pidl("memcpy(${r}$e->{NAME}, ${i}$e->{NAME}, sizeof(${r}$e->{NAME}));");
} else {
$self->pidl("${r}$e->{NAME} = ${i}$e->{NAME};");
}
}
sub ParseInvalidResponse($$)
{
my ($self, $type) = @_;
if ($type eq "sync") {
$self->pidl("return NT_STATUS_INVALID_NETWORK_RESPONSE;");
} elsif ($type eq "async") {
$self->pidl("tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);");
$self->pidl("return;");
} else {
die("ParseInvalidResponse($type)");
}
}
sub ParseOutputArgument($$$$$$)
{
my ($self, $fn, $e, $r, $o, $invalid_response_type) = @_;
my $level = 0;
if ($e->{LEVELS}[0]->{TYPE} ne "POINTER" and $e->{LEVELS}[0]->{TYPE} ne "ARRAY") {
fatal($e->{ORIGINAL}, "[out] argument is not a pointer or array");
return;
}
if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
$level = 1;
if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") {
$self->pidl("if ($o$e->{NAME} && ${r}out.$e->{NAME}) {");
$self->indent;
}
}
if ($e->{LEVELS}[$level]->{TYPE} eq "ARRAY") {
# This is a call to GenerateFunctionInEnv intentionally.
# Since the data is being copied into a user-provided data
# structure, the user should be able to know the size beforehand
# to allocate a structure of the right size.
my $in_env = GenerateFunctionInEnv($fn, $r);
my $out_env = GenerateFunctionOutEnv($fn, $r);
my $l = $e->{LEVELS}[$level];
my $in_var = undef;
if (grep(/in/, @{$e->{DIRECTION}})) {
$in_var = ParseExpr($e->{NAME}, $in_env, $e->{ORIGINAL});
}
my $out_var = ParseExpr($e->{NAME}, $out_env, $e->{ORIGINAL});
my $in_size_is = undef;
my $out_size_is = undef;
my $out_length_is = undef;
my $avail_len = undef;
my $needed_len = undef;
$self->pidl("{");
$self->indent;
my $copy_len_var = "_copy_len_$e->{NAME}";
$self->pidl("size_t $copy_len_var;");
if (not defined($l->{SIZE_IS})) {
if (not $l->{IS_ZERO_TERMINATED}) {
fatal($e->{ORIGINAL}, "no size known for [out] array `$e->{NAME}'");
}
if (has_property($e, "charset")) {
$avail_len = "ndr_charset_length($in_var, CH_UNIX)";
$needed_len = "ndr_charset_length($out_var, CH_UNIX)";
} else {
$avail_len = "ndr_string_length($in_var, sizeof(*$in_var))";
$needed_len = "ndr_string_length($out_var, sizeof(*$out_var))";
}
$in_size_is = "";
$out_size_is = "";
$out_length_is = "";
} else {
$in_size_is = ParseExpr($l->{SIZE_IS}, $in_env, $e->{ORIGINAL});
$out_size_is = ParseExpr($l->{SIZE_IS}, $out_env, $e->{ORIGINAL});
$out_length_is = $out_size_is;
if (defined($l->{LENGTH_IS})) {
$out_length_is = ParseExpr($l->{LENGTH_IS}, $out_env, $e->{ORIGINAL});
}
if (has_property($e, "charset")) {
if (defined($in_var)) {
$avail_len = "ndr_charset_length($in_var, CH_UNIX)";
} else {
$avail_len = $out_length_is;
}
$needed_len = "ndr_charset_length($out_var, CH_UNIX)";
}
}
if ($out_size_is ne $in_size_is) {
$self->pidl("if (($out_size_is) > ($in_size_is)) {");
$self->indent;
$self->ParseInvalidResponse($invalid_response_type);
$self->deindent;
$self->pidl("}");
}
if ($out_length_is ne $out_size_is) {
$self->pidl("if (($out_length_is) > ($out_size_is)) {");
$self->indent;
$self->ParseInvalidResponse($invalid_response_type);
$self->deindent;
$self->pidl("}");
}
if (defined($needed_len)) {
$self->pidl("$copy_len_var = $needed_len;");
$self->pidl("if ($copy_len_var > $avail_len) {");
$self->indent;
$self->ParseInvalidResponse($invalid_response_type);
$self->deindent;
$self->pidl("}");
} else {
$self->pidl("$copy_len_var = $out_length_is;");
}
if (has_property($e, "charset")) {
$self->pidl("memcpy(discard_const_p(uint8_t *, $o$e->{NAME}), $out_var, $copy_len_var * sizeof(*$o$e->{NAME}));");
} else {
$self->pidl("memcpy($o$e->{NAME}, $out_var, $copy_len_var * sizeof(*$o$e->{NAME}));");
}
$self->deindent;
$self->pidl("}");
} else {
$self->pidl("*$o$e->{NAME} = *${r}out.$e->{NAME};");
}
if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
if ($e->{LEVELS}[0]->{POINTER_TYPE} ne "ref") {
$self->deindent;
$self->pidl("}");
}
}
}
sub ParseFunction_State($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $state_str = "struct dcerpc_$name\_state";
my $done_fn = "dcerpc_$name\_done";
$self->pidl("$state_str {");
$self->indent;
$self->pidl("struct $name orig;");
$self->pidl("struct $name tmp;");
$self->pidl("TALLOC_CTX *out_mem_ctx;");
$self->deindent;
$self->pidl("};");
$self->pidl("");
$self->pidl("static void $done_fn(struct tevent_req *subreq);");
$self->pidl("");
}
sub ParseFunction_Send($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $fn_args = "";
my $state_str = "struct dcerpc_$name\_state";
my $done_fn = "dcerpc_$name\_done";
my $out_mem_ctx = "dcerpc_$name\_out_memory";
my $fn_str = "struct tevent_req *dcerpc_$name\_send";
my $pad = genpad($fn_str);
$fn_args .= "TALLOC_CTX *mem_ctx";
$fn_args .= ",\n" . $pad . "struct tevent_context *ev";
$fn_args .= ",\n" . $pad . "struct dcerpc_binding_handle *h";
foreach (@{$fn->{ELEMENTS}}) {
my $dir = ElementDirection($_);
my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
$fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req;");
$self->pidl("$state_str *state;");
$self->pidl("struct tevent_req *subreq;");
$self->pidl("");
$self->pidl("req = tevent_req_create(mem_ctx, &state,");
$self->pidl("\t\t\t$state_str);");
$self->pidl("if (req == NULL) {");
$self->indent;
$self->pidl("return NULL;");
$self->deindent;
$self->pidl("}");
$self->pidl("state->out_mem_ctx = NULL;");
$self->pidl("");
$self->pidl("/* In parameters */");
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless (grep(/in/, @{$e->{DIRECTION}}));
$self->ParseCopyArgument($fn, $e, "state->orig.in.", "_");
}
$self->pidl("");
my $out_params = 0;
$self->pidl("/* Out parameters */");
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless grep(/out/, @{$e->{DIRECTION}});
$self->ParseCopyArgument($fn, $e, "state->orig.out.", "_");
next if ContainsPipe($e, $e->{LEVELS}[0]);
$out_params++;
}
$self->pidl("");
if (defined($fn->{RETURN_TYPE})) {
$self->pidl("/* Result */");
$self->pidl("ZERO_STRUCT(state->orig.out.result);");
$self->pidl("");
}
if ($out_params > 0) {
$self->pidl("state->out_mem_ctx = talloc_named_const(state, 0,");
$self->pidl("\t\t \"$out_mem_ctx\");");
$self->pidl("if (tevent_req_nomem(state->out_mem_ctx, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
$self->pidl("/* make a temporary copy, that we pass to the dispatch function */");
$self->pidl("state->tmp = state->orig;");
$self->pidl("");
$self->pidl("subreq = dcerpc_$name\_r_send(state, ev, h, &state->tmp);");
$self->pidl("if (tevent_req_nomem(subreq, req)) {");
$self->indent;
$self->pidl("return tevent_req_post(req, ev);");
$self->deindent;
$self->pidl("}");
$self->pidl("tevent_req_set_callback(subreq, $done_fn, req);");
$self->pidl("return req;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction_Done($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $state_str = "struct dcerpc_$name\_state";
my $done_fn = "dcerpc_$name\_done";
$self->pidl("static void $done_fn(struct tevent_req *subreq)");
$self->pidl("{");
$self->indent;
$self->pidl("struct tevent_req *req = tevent_req_callback_data(");
$self->pidl("\tsubreq, struct tevent_req);");
$self->pidl("$state_str *state = tevent_req_data(");
$self->pidl("\treq, $state_str);");
$self->pidl("NTSTATUS status;");
$self->pidl("TALLOC_CTX *mem_ctx;");
$self->pidl("");
$self->pidl("if (state->out_mem_ctx) {");
$self->indent;
$self->pidl("mem_ctx = state->out_mem_ctx;");
$self->deindent;
$self->pidl("} else {");
$self->indent;
$self->pidl("mem_ctx = state;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("status = dcerpc_$name\_r_recv(subreq, mem_ctx);");
$self->pidl("TALLOC_FREE(subreq);");
$self->pidl("if (!NT_STATUS_IS_OK(status)) {");
$self->indent;
$self->pidl("tevent_req_nterror(req, status);");
$self->pidl("return;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("/* Copy out parameters */");
foreach my $e (@{$fn->{ELEMENTS}}) {
next if ContainsPipe($e, $e->{LEVELS}[0]);
next unless (grep(/out/, @{$e->{DIRECTION}}));
$self->ParseOutputArgument($fn, $e,
"state->tmp.",
"state->orig.out.",
"async");
}
$self->pidl("");
if (defined($fn->{RETURN_TYPE})) {
$self->pidl("/* Copy result */");
$self->pidl("state->orig.out.result = state->tmp.out.result;");
$self->pidl("");
}
$self->pidl("/* Reset temporary structure */");
$self->pidl("ZERO_STRUCT(state->tmp);");
$self->pidl("");
$self->pidl("tevent_req_done(req);");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction_Recv($$$$)
{
my ($self, $if, $fn, $name) = @_;
my $fn_args = "";
my $state_str = "struct dcerpc_$name\_state";
my $fn_str = "NTSTATUS dcerpc_$name\_recv";
my $pad = genpad($fn_str);
$fn_args .= "struct tevent_req *req,\n" . $pad . "TALLOC_CTX *mem_ctx";
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . mapTypeName($fn->{RETURN_TYPE}). " *result";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
$self->pidl("$state_str *state = tevent_req_data(");
$self->pidl("\treq, $state_str);");
$self->pidl("NTSTATUS status;");
$self->pidl("");
$self->pidl("if (tevent_req_is_nterror(req, &status)) {");
$self->indent;
$self->pidl("tevent_req_received(req);");
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("/* Steal possible out parameters to the callers context */");
$self->pidl("talloc_steal(mem_ctx, state->out_mem_ctx);");
$self->pidl("");
if (defined($fn->{RETURN_TYPE})) {
$self->pidl("/* Return result */");
$self->pidl("*result = state->orig.out.result;");
$self->pidl("");
}
$self->pidl("tevent_req_received(req);");
$self->pidl("return NT_STATUS_OK;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
sub ParseFunction_Sync($$$$)
{
my ($self, $if, $fn, $name) = @_;
if ($self->ParseFunctionHasPipes($fn)) {
$self->pidl_both("/*");
$self->pidl_both(" * The following function is skipped because");
$self->pidl_both(" * it uses pipes:");
$self->pidl_both(" *");
$self->pidl_both(" * dcerpc_$name()");
$self->pidl_both(" */");
$self->pidl_both("");
return;
}
my $uname = uc $name;
my $fn_args = "";
my $fn_str = "NTSTATUS dcerpc_$name";
my $pad = genpad($fn_str);
$fn_args .= "struct dcerpc_binding_handle *h,\n" . $pad . "TALLOC_CTX *mem_ctx";
foreach (@{$fn->{ELEMENTS}}) {
my $dir = ElementDirection($_);
my $prop = HeaderProperties($_->{PROPERTIES}, ["in", "out"]);
$fn_args .= ",\n" . $pad . DeclLong($_, "_") . " /* $dir $prop */";
}
if (defined($fn->{RETURN_TYPE})) {
$fn_args .= ",\n" . $pad . mapTypeName($fn->{RETURN_TYPE}). " *result";
}
$self->fn_declare("$fn_str($fn_args)");
$self->pidl("{");
$self->indent;
$self->pidl("struct $name r;");
$self->pidl("NTSTATUS status;");
$self->pidl("");
$self->pidl("/* In parameters */");
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless (grep(/in/, @{$e->{DIRECTION}}));
$self->ParseCopyArgument($fn, $e, "r.in.", "_");
}
$self->pidl("");
$self->pidl("status = dcerpc_$name\_r(h, mem_ctx, &r);");
$self->pidl("if (!NT_STATUS_IS_OK(status)) {");
$self->indent;
$self->pidl("return status;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
$self->pidl("/* Return variables */");
foreach my $e (@{$fn->{ELEMENTS}}) {
next if ContainsPipe($e, $e->{LEVELS}[0]);
next unless (grep(/out/, @{$e->{DIRECTION}}));
$self->ParseOutputArgument($fn, $e, "r.", "_", "sync");
}
$self->pidl("");
$self->pidl("/* Return result */");
if ($fn->{RETURN_TYPE}) {
$self->pidl("*result = r.out.result;");
}
$self->pidl("");
$self->pidl("return NT_STATUS_OK;");
$self->deindent;
$self->pidl("}");
$self->pidl("");
}
#####################################################################
# parse a function
sub ParseFunction($$$)
{
my ($self, $if, $fn) = @_;
if ($self->ParseFunctionHasPipes($fn)) {
$self->pidl_both("/*");
$self->pidl_both(" * The following function is skipped because");
$self->pidl_both(" * it uses pipes:");
$self->pidl_both(" *");
$self->pidl_both(" * dcerpc_$fn->{NAME}_r_send()");
$self->pidl_both(" * dcerpc_$fn->{NAME}_r_recv()");
$self->pidl_both(" * dcerpc_$fn->{NAME}_r()");
$self->pidl_both(" *");
$self->pidl_both(" * dcerpc_$fn->{NAME}_send()");
$self->pidl_both(" * dcerpc_$fn->{NAME}_recv()");
$self->pidl_both(" * dcerpc_$fn->{NAME}()");
$self->pidl_both(" */");
$self->pidl_both("");
warning($fn->{ORIGINAL}, "$fn->{NAME}: dcerpc client does not support pipe yet");
return;
}
$self->ParseFunction_r_State($if, $fn, $fn->{NAME});
$self->ParseFunction_r_Send($if, $fn, $fn->{NAME});
$self->ParseFunction_r_Done($if, $fn, $fn->{NAME});
$self->ParseFunction_r_Recv($if, $fn, $fn->{NAME});
$self->ParseFunction_r_Sync($if, $fn, $fn->{NAME});
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless (grep(/out/, @{$e->{DIRECTION}}));
my $reason = "is not a pointer or array";
# TODO: make this fatal at NDR level
if ($e->{LEVELS}[0]->{TYPE} eq "POINTER") {
if ($e->{LEVELS}[1]->{TYPE} eq "DATA" and
$e->{LEVELS}[1]->{DATA_TYPE} eq "string") {
$reason = "is a pointer to type 'string'";
} elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY" and
$e->{LEVELS}[1]->{IS_ZERO_TERMINATED}) {
next;
} elsif ($e->{LEVELS}[1]->{TYPE} eq "ARRAY" and
not defined($e->{LEVELS}[1]->{SIZE_IS})) {
$reason = "is a pointer to an unsized array";
} else {
next;
}
}
if ($e->{LEVELS}[0]->{TYPE} eq "ARRAY") {
if (not defined($e->{LEVELS}[0]->{SIZE_IS})) {
$reason = "is an unsized array";
} else {
next;
}
}
$self->pidl_both("/*");
$self->pidl_both(" * The following functions are skipped because");
$self->pidl_both(" * an [out] argument $e->{NAME} $reason:");
$self->pidl_both(" *");
$self->pidl_both(" * dcerpc_$fn->{NAME}_send()");
$self->pidl_both(" * dcerpc_$fn->{NAME}_recv()");
$self->pidl_both(" * dcerpc_$fn->{NAME}()");
$self->pidl_both(" */");
$self->pidl_both("");
error($e->{ORIGINAL}, "$fn->{NAME}: [out] argument '$e->{NAME}' $reason, skip client functions");
return;
}
$self->ParseFunction_State($if, $fn, $fn->{NAME});
$self->ParseFunction_Send($if, $fn, $fn->{NAME});
$self->ParseFunction_Done($if, $fn, $fn->{NAME});
$self->ParseFunction_Recv($if, $fn, $fn->{NAME});
$self->ParseFunction_Sync($if, $fn, $fn->{NAME});
$self->pidl_hdr("");
}
my %done;
#####################################################################
# parse the interface definitions
sub ParseInterface($$)
{
my ($self, $if) = @_;
my $ifu = uc($if->{NAME});
$self->pidl_hdr("#ifndef _HEADER_RPC_$if->{NAME}");
$self->pidl_hdr("#define _HEADER_RPC_$if->{NAME}");
$self->pidl_hdr("");
if (defined $if->{PROPERTIES}->{uuid}) {
$self->pidl_hdr("extern const struct ndr_interface_table ndr_table_$if->{NAME};");
$self->pidl_hdr("");
}
$self->pidl("/* $if->{NAME} - client functions generated by pidl */");
$self->pidl("");
foreach my $fn (@{$if->{FUNCTIONS}}) {
next if defined($done{$fn->{NAME}});
next if has_property($fn, "noopnum");
next if has_property($fn, "todo");
$self->ParseFunction($if, $fn);
$done{$fn->{NAME}} = 1;
}
$self->pidl_hdr("#endif /* _HEADER_RPC_$if->{NAME} */");
}
sub Parse($$$$$$)
{
my($self,$ndr,$header,$ndr_header,$client_header) = @_;
$self->pidl("/* client functions auto-generated by pidl */");
$self->pidl("");
if (is_intree()) {
$self->pidl("#include \"includes.h\"");
} else {
$self->pidl("#ifndef _GNU_SOURCE");
$self->pidl("#define _GNU_SOURCE");
$self->pidl("#endif");
$self->pidl("#include <stdio.h>");
$self->pidl("#include <stdbool.h>");
$self->pidl("#include <stdlib.h>");
$self->pidl("#include <stdint.h>");
$self->pidl("#include <stdarg.h>");
$self->pidl("#include <string.h>");
$self->pidl("#include <core/ntstatus.h>");
}
$self->pidl("#include <tevent.h>");
$self->pidl(choose_header("lib/util/tevent_ntstatus.h", "util/tevent_ntstatus.h")."");
$self->pidl("#include \"$ndr_header\"");
$self->pidl("#include \"$client_header\"");
$self->pidl("");
$self->pidl_hdr(choose_header("librpc/rpc/dcerpc.h", "dcerpc.h")."");
$self->pidl_hdr("#include \"$header\"");
foreach my $x (@{$ndr}) {
($x->{TYPE} eq "INTERFACE") && $self->ParseInterface($x);
}
return ($self->{res},$self->{res_hdr});
}
1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,334 @@
###################################################
# server boilerplate generator
# Copyright tridge@samba.org 2003
# Copyright metze@samba.org 2004
# released under the GNU GPL
package Parse::Pidl::Samba4::NDR::Server;
use strict;
use Parse::Pidl::Util;
use vars qw($VERSION);
$VERSION = '0.01';
my($res);
sub pidl($)
{
$res .= shift;
}
#####################################################
# generate the switch statement for function dispatch
sub gen_dispatch_switch($)
{
my $interface = shift;
foreach my $fn (@{$interface->{FUNCTIONS}}) {
next if not defined($fn->{OPNUM});
pidl "\tcase $fn->{OPNUM}: {\n";
pidl "\t\tstruct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;\n";
pidl "\t\tif (DEBUGLEVEL >= 10) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r2);\n";
pidl "\t\t}\n";
if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
pidl "\t\tr2->out.result = dcesrv_$fn->{NAME}(dce_call, mem_ctx, r2);\n";
} else {
pidl "\t\tdcesrv_$fn->{NAME}(dce_call, mem_ctx, r2);\n";
}
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $fn->{NAME} will reply async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
}
}
#####################################################
# generate the switch statement for function reply
sub gen_reply_switch($)
{
my $interface = shift;
foreach my $fn (@{$interface->{FUNCTIONS}}) {
next if not defined($fn->{OPNUM});
pidl "\tcase $fn->{OPNUM}: {\n";
pidl "\t\tstruct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;\n";
pidl "\t\tif (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {\n";
pidl "\t\t\tDEBUG(5,(\"function $fn->{NAME} replied async\\n\"));\n";
pidl "\t\t}\n";
pidl "\t\tif (DEBUGLEVEL >= 10 && dce_call->fault_code == 0) {\n";
pidl "\t\t\tNDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);\n";
pidl "\t\t}\n";
pidl "\t\tif (dce_call->fault_code != 0) {\n";
pidl "\t\t\tDEBUG(2,(\"dcerpc_fault %s in $fn->{NAME}\\n\", dcerpc_errstr(mem_ctx, dce_call->fault_code)));\n";
pidl "\t\t}\n";
pidl "\t\tbreak;\n\t}\n";
}
}
#####################################################################
# produce boilerplate code for a interface
sub Boilerplate_Iface($)
{
my($interface) = shift;
my $name = $interface->{NAME};
my $uname = uc $name;
my $uuid = lc($interface->{UUID});
my $if_version = $interface->{VERSION};
pidl "
static NTSTATUS $name\__op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
{
#ifdef DCESRV_INTERFACE_$uname\_BIND
return DCESRV_INTERFACE_$uname\_BIND(dce_call,iface);
#else
return NT_STATUS_OK;
#endif
}
static void $name\__op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
{
#ifdef DCESRV_INTERFACE_$uname\_UNBIND
DCESRV_INTERFACE_$uname\_UNBIND(context, iface);
#else
return;
#endif
}
static NTSTATUS $name\__op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
{
enum ndr_err_code ndr_err;
uint16_t opnum = dce_call->pkt.u.request.opnum;
dce_call->fault_code = 0;
if (opnum >= ndr_table_$name.num_calls) {
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
return NT_STATUS_NET_WRITE_FAULT;
}
*r = talloc_named(mem_ctx,
ndr_table_$name.calls[opnum].struct_size,
\"struct %s\",
ndr_table_$name.calls[opnum].name);
NT_STATUS_HAVE_NO_MEMORY(*r);
/* unravel the NDR for the packet */
ndr_err = ndr_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, *r);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
dcerpc_log_packet(dce_call->conn->packet_log_dir,
&ndr_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
switch (opnum) {
";
gen_dispatch_switch($interface);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(dce_call->conn->packet_log_dir,
&ndr_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
{
uint16_t opnum = dce_call->pkt.u.request.opnum;
switch (opnum) {
";
gen_reply_switch($interface);
pidl "
default:
dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
break;
}
if (dce_call->fault_code != 0) {
dcerpc_log_packet(dce_call->conn->packet_log_dir,
&ndr_table_$name, opnum, NDR_IN,
&dce_call->pkt.u.request.stub_and_verifier);
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
static NTSTATUS $name\__op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
{
enum ndr_err_code ndr_err;
uint16_t opnum = dce_call->pkt.u.request.opnum;
ndr_err = ndr_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
dce_call->fault_code = DCERPC_FAULT_NDR;
return NT_STATUS_NET_WRITE_FAULT;
}
return NT_STATUS_OK;
}
const struct dcesrv_interface dcesrv\_$name\_interface = {
.name = \"$name\",
.syntax_id = {".print_uuid($uuid).",$if_version},
.bind = $name\__op_bind,
.unbind = $name\__op_unbind,
.ndr_pull = $name\__op_ndr_pull,
.dispatch = $name\__op_dispatch,
.reply = $name\__op_reply,
.ndr_push = $name\__op_ndr_push
};
";
}
#####################################################################
# produce boilerplate code for an endpoint server
sub Boilerplate_Ep_Server($)
{
my($interface) = shift;
my $name = $interface->{NAME};
my $uname = uc $name;
pidl "
static NTSTATUS $name\__op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
int i;
for (i=0;i<ndr_table_$name.endpoints->count;i++) {
NTSTATUS ret;
const char *name = ndr_table_$name.endpoints->names[i];
ret = dcesrv_interface_register(dce_ctx, name, &dcesrv_$name\_interface, NULL);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1,(\"$name\_op_init_server: failed to register endpoint \'%s\'\\n\",name));
return ret;
}
}
return NT_STATUS_OK;
}
static bool $name\__op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
{
if (dcesrv_$name\_interface.syntax_id.if_version == if_version &&
GUID_equal(\&dcesrv\_$name\_interface.syntax_id.uuid, uuid)) {
memcpy(iface,&dcesrv\_$name\_interface, sizeof(*iface));
return true;
}
return false;
}
static bool $name\__op_interface_by_name(struct dcesrv_interface *iface, const char *name)
{
if (strcmp(dcesrv_$name\_interface.name, name)==0) {
memcpy(iface, &dcesrv_$name\_interface, sizeof(*iface));
return true;
}
return false;
}
NTSTATUS dcerpc_server_$name\_init(void)
{
NTSTATUS ret;
struct dcesrv_endpoint_server ep_server;
/* fill in our name */
ep_server.name = \"$name\";
/* fill in all the operations */
ep_server.init_server = $name\__op_init_server;
ep_server.interface_by_uuid = $name\__op_interface_by_uuid;
ep_server.interface_by_name = $name\__op_interface_by_name;
/* register ourselves with the DCERPC subsystem. */
ret = dcerpc_register_ep_server(&ep_server);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(0,(\"Failed to register \'$name\' endpoint server!\\n\"));
return ret;
}
return ret;
}
";
}
#####################################################################
# dcerpc server boilerplate from a parsed IDL structure
sub ParseInterface($)
{
my($interface) = shift;
my $count = 0;
$res .= "NTSTATUS dcerpc_server_$interface->{NAME}\_init(void);\n";
$res .= "\n";
if (!defined $interface->{PROPERTIES}->{uuid}) {
return $res;
}
if (!defined $interface->{PROPERTIES}->{version}) {
$interface->{PROPERTIES}->{version} = "0.0";
}
foreach my $fn (@{$interface->{FUNCTIONS}}) {
if (defined($fn->{OPNUM})) { $count++; }
}
if ($count == 0) {
return $res;
}
$res .= "/* $interface->{NAME} - dcerpc server boilerplate generated by pidl */\n\n";
Boilerplate_Iface($interface);
Boilerplate_Ep_Server($interface);
return $res;
}
sub Parse($$)
{
my($ndr,$header) = @_;
$res = "";
$res .= "/* server functions auto-generated by pidl */\n";
$res .= "#include \"$header\"\n";
$res .= "\n";
foreach my $x (@{$ndr}) {
ParseInterface($x) if ($x->{TYPE} eq "INTERFACE" and not defined($x->{PROPERTIES}{object}));
}
return $res;
}
1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
###################################################
# Trivial Parser Generator
# Copyright jelmer@samba.org 2005-2007
# released under the GNU GPL
package Parse::Pidl::Samba4::TDR;
use Parse::Pidl qw(fatal);
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
use Parse::Pidl::Samba4 qw(is_intree choose_header);
use Parse::Pidl::Typelist qw(mapTypeName);
use Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(ParserType $ret $ret_hdr);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
sub new($) {
my ($class) = shift;
my $self = { ret => "", ret_hdr => "", tabs => "" };
bless($self, $class);
}
sub indent($) { my $self = shift; $self->{tabs}.="\t"; }
sub deindent($) { my $self = shift; $self->{tabs} = substr($self->{tabs}, 1); }
sub pidl($$) { my $self = shift; $self->{ret} .= $self->{tabs}.(shift)."\n"; }
sub pidl_hdr($$) { my $self = shift; $self->{ret_hdr} .= (shift)."\n"; }
sub typearg($) {
my $t = shift;
return(", const char *name") if ($t eq "print");
return(", TALLOC_CTX *mem_ctx") if ($t eq "pull");
return("");
}
sub fn_declare($$$)
{
my ($self, $p, $d) = @_;
if ($p) {
$self->pidl($d); $self->pidl_hdr("$d;");
} else {
$self->pidl("static $d");
}
}
sub ContainsArray($)
{
my $e = shift;
foreach (@{$e->{ELEMENTS}}) {
next if (has_property($_, "charset") and
scalar(@{$_->{ARRAY_LEN}}) == 1);
return 1 if (defined($_->{ARRAY_LEN}) and
scalar(@{$_->{ARRAY_LEN}}) > 0);
}
return 0;
}
sub ParserElement($$$$)
{
my ($self, $e,$t,$env) = @_;
my $switch = "";
my $array = "";
my $name = "";
my $mem_ctx = "mem_ctx";
fatal($e,"Pointers not supported in TDR") if ($e->{POINTERS} > 0);
fatal($e,"size_is() not supported in TDR") if (has_property($e, "size_is"));
fatal($e,"length_is() not supported in TDR") if (has_property($e, "length_is"));
if ($t eq "print") {
$name = ", \"$e->{NAME}\"$array";
}
if (has_property($e, "flag")) {
$self->pidl("{");
$self->indent;
$self->pidl("uint32_t saved_flags = tdr->flags;");
$self->pidl("tdr->flags |= $e->{PROPERTIES}->{flag};");
}
if (has_property($e, "charset")) {
fatal($e,"charset() on non-array element") unless (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0);
my $len = ParseExpr(@{$e->{ARRAY_LEN}}[0], $env, $e);
if ($len eq "*") { $len = "-1"; }
$name = ", mem_ctx" if ($t eq "pull");
$self->pidl("TDR_CHECK(tdr_$t\_charset(tdr$name, &v->$e->{NAME}, $len, sizeof($e->{TYPE}_t), CH_$e->{PROPERTIES}->{charset}));");
return;
}
if (has_property($e, "switch_is")) {
$switch = ", " . ParseExpr($e->{PROPERTIES}->{switch_is}, $env, $e);
}
if (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0) {
my $len = ParseExpr($e->{ARRAY_LEN}[0], $env, $e);
if ($t eq "pull" and not is_constant($len)) {
$self->pidl("TDR_ALLOC(mem_ctx, v->$e->{NAME}, $len);");
$mem_ctx = "v->$e->{NAME}";
}
$self->pidl("for (i = 0; i < $len; i++) {");
$self->indent;
$array = "[i]";
}
if ($t eq "pull") {
$name = ", $mem_ctx";
}
if (has_property($e, "value") && $t eq "push") {
$self->pidl("v->$e->{NAME} = ".ParseExpr($e->{PROPERTIES}->{value}, $env, $e).";");
}
$self->pidl("TDR_CHECK(tdr_$t\_$e->{TYPE}(tdr$name$switch, &v->$e->{NAME}$array));");
if ($array) { $self->deindent; $self->pidl("}"); }
if (has_property($e, "flag")) {
$self->pidl("tdr->flags = saved_flags;");
$self->deindent;
$self->pidl("}");
}
}
sub ParserStruct($$$$$)
{
my ($self, $e,$t,$p) = @_;
$self->fn_declare($p,"NTSTATUS tdr_$t\_$e->{NAME} (struct tdr_$t *tdr".typearg($t).", struct $e->{NAME} *v)");
$self->pidl("{"); $self->indent;
$self->pidl("int i;") if (ContainsArray($e));
if ($t eq "print") {
$self->pidl("tdr->print(tdr, \"\%-25s: struct $e->{NAME}\", name);");
$self->pidl("tdr->level++;");
}
my %env = map { $_->{NAME} => "v->$_->{NAME}" } @{$e->{ELEMENTS}};
$env{"this"} = "v";
$self->ParserElement($_, $t, \%env) foreach (@{$e->{ELEMENTS}});
if ($t eq "print") {
$self->pidl("tdr->level--;");
}
$self->pidl("return NT_STATUS_OK;");
$self->deindent; $self->pidl("}");
}
sub ParserUnion($$$$)
{
my ($self, $e,$t,$p) = @_;
$self->fn_declare($p,"NTSTATUS tdr_$t\_$e->{NAME}(struct tdr_$t *tdr".typearg($t).", int level, union $e->{NAME} *v)");
$self->pidl("{"); $self->indent;
$self->pidl("int i;") if (ContainsArray($e));
if ($t eq "print") {
$self->pidl("tdr->print(tdr, \"\%-25s: union $e->{NAME}\", name);");
$self->pidl("tdr->level++;");
}
$self->pidl("switch (level) {"); $self->indent;
foreach (@{$e->{ELEMENTS}}) {
if (has_property($_, "case")) {
$self->pidl("case " . $_->{PROPERTIES}->{case} . ":");
} elsif (has_property($_, "default")) {
$self->pidl("default:");
}
$self->indent; $self->ParserElement($_, $t, {}); $self->deindent;
$self->pidl("break;");
}
$self->deindent; $self->pidl("}");
if ($t eq "print") {
$self->pidl("tdr->level--;");
}
$self->pidl("return NT_STATUS_OK;\n");
$self->deindent; $self->pidl("}");
}
sub ParserBitmap($$$$)
{
my ($self,$e,$t,$p) = @_;
return if ($p);
$self->pidl("#define tdr_$t\_$e->{NAME} tdr_$t\_" . Parse::Pidl::Typelist::bitmap_type_fn($e));
}
sub ParserEnum($$$$)
{
my ($self,$e,$t,$p) = @_;
my $bt = Parse::Pidl::Typelist::enum_type_fn($e);
my $mt = mapTypeName($bt);
$self->fn_declare($p, "NTSTATUS tdr_$t\_$e->{NAME} (struct tdr_$t *tdr".typearg($t).", enum $e->{NAME} *v)");
$self->pidl("{");
if ($t eq "pull") {
$self->pidl("\t$mt r;");
$self->pidl("\tTDR_CHECK(tdr_$t\_$bt(tdr, mem_ctx, \&r));");
$self->pidl("\t*v = r;");
} elsif ($t eq "push") {
$self->pidl("\tTDR_CHECK(tdr_$t\_$bt(tdr, ($mt *)v));");
} elsif ($t eq "print") {
$self->pidl("\t/* FIXME */");
}
$self->pidl("\treturn NT_STATUS_OK;");
$self->pidl("}");
}
sub ParserTypedef($$$$)
{
my ($self, $e,$t,$p) = @_;
$self->ParserType($e->{DATA},$t);
}
sub ParserType($$$)
{
my ($self, $e,$t) = @_;
return if (has_property($e, "no$t"));
my $handlers = {
STRUCT => \&ParserStruct, UNION => \&ParserUnion,
ENUM => \&ParserEnum, BITMAP => \&ParserBitmap,
TYPEDEF => \&ParserTypedef
};
$handlers->{$e->{TYPE}}->($self, $e, $t, has_property($e, "public"))
if (defined($handlers->{$e->{TYPE}}));
$self->pidl("");
}
sub ParserInterface($$)
{
my ($self,$x) = @_;
$self->pidl_hdr("#ifndef __TDR_$x->{NAME}_HEADER__");
$self->pidl_hdr("#define __TDR_$x->{NAME}_HEADER__");
foreach (@{$x->{DATA}}) {
$self->ParserType($_, "pull");
$self->ParserType($_, "push");
$self->ParserType($_, "print");
}
$self->pidl_hdr("#endif /* __TDR_$x->{NAME}_HEADER__ */");
}
sub Parser($$$$)
{
my ($self,$idl,$hdrname,$baseheader) = @_;
$self->pidl("/* autogenerated by pidl */");
if (is_intree()) {
$self->pidl("#include \"includes.h\"");
} else {
$self->pidl("#include <stdio.h>");
$self->pidl("#include <stdbool.h>");
$self->pidl("#include <stdlib.h>");
$self->pidl("#include <stdint.h>");
$self->pidl("#include <stdarg.h>");
$self->pidl("#include <string.h>");
$self->pidl("#include <core/ntstatus.h>");
}
$self->pidl("#include \"$hdrname\"");
$self->pidl("");
$self->pidl_hdr("/* autogenerated by pidl */");
$self->pidl_hdr("#include \"$baseheader\"");
$self->pidl_hdr(choose_header("lib/tdr/tdr.h", "tdr.h"));
$self->pidl_hdr("");
foreach (@$idl) { $self->ParserInterface($_) if ($_->{TYPE} eq "INTERFACE"); }
return ($self->{ret_hdr}, $self->{ret});
}
1;

View File

@ -0,0 +1,98 @@
###################################################
# server template function generator
# Copyright tridge@samba.org 2003
# released under the GNU GPL
package Parse::Pidl::Samba4::Template;
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
my($res);
#####################################################################
# produce boilerplate code for a interface
sub Template($)
{
my($interface) = shift;
my($data) = $interface->{DATA};
my $name = $interface->{NAME};
$res .=
"/*
Unix SMB/CIFS implementation.
endpoint server for the $name pipe
Copyright (C) YOUR NAME HERE YEAR
This program 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 3 of the License, or
(at your option) any later version.
This program 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 program. If not, see <http://www.gnu.org/licenses/>.
*/
#include \"includes.h\"
#include \"rpc_server/dcerpc_server.h\"
#include \"librpc/gen_ndr/ndr_$name.h\"
#include \"rpc_server/common/common.h\"
";
foreach my $d (@{$data}) {
if ($d->{TYPE} eq "FUNCTION") {
my $fname = $d->{NAME};
$res .=
"
/*
$fname
*/
static $d->{RETURN_TYPE} dcesrv_$fname(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct $fname *r)
{
";
if ($d->{RETURN_TYPE} eq "void") {
$res .= "\tDCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);\n";
} else {
$res .= "\tDCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);\n";
}
$res .= "}
";
}
}
$res .=
"
/* include the generated boilerplate */
#include \"librpc/gen_ndr/ndr_$name\_s.c\"
"
}
#####################################################################
# parse a parsed IDL structure back into an IDL file
sub Parse($)
{
my($idl) = shift;
$res = "";
foreach my $x (@{$idl}) {
($x->{TYPE} eq "INTERFACE") &&
Template($x);
}
return $res;
}
1;

View File

@ -0,0 +1,372 @@
###################################################
# Samba4 parser generator for IDL structures
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Typelist;
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(hasType getType resolveType mapTypeName scalar_is_reference expandAlias
mapScalarType maybeMapScalarType addType typeIs is_signed is_scalar is_struct enum_type_fn
bitmap_type_fn mapType typeHasBody is_fixed_size_scalar
);
use vars qw($VERSION);
$VERSION = '0.01';
use Parse::Pidl::Util qw(has_property);
use strict;
my %types = ();
my @reference_scalars = (
"string", "string_array", "nbt_string", "dns_string",
"wrepl_nbt_name", "dnsp_name", "dnsp_string",
"ipv4address", "ipv6address"
);
my @non_fixed_size_scalars = (
"string", "string_array", "nbt_string", "dns_string",
"wrepl_nbt_name", "dnsp_name", "dnsp_string"
);
# a list of known scalar types
my %scalars = (
"void" => "void",
"char" => "char",
"int8" => "int8_t",
"uint8" => "uint8_t",
"int16" => "int16_t",
"uint16" => "uint16_t",
"int1632" => "int16_t",
"uint1632" => "uint16_t",
"int32" => "int32_t",
"uint32" => "uint32_t",
"int3264" => "int32_t",
"uint3264" => "uint32_t",
"hyper" => "uint64_t",
"dlong" => "int64_t",
"udlong" => "uint64_t",
"udlongr" => "uint64_t",
"double" => "double",
"pointer" => "void*",
"DATA_BLOB" => "DATA_BLOB",
"string" => "const char *",
"string_array" => "const char **",
"time_t" => "time_t",
"uid_t" => "uid_t",
"gid_t" => "gid_t",
"NTTIME" => "NTTIME",
"NTTIME_1sec" => "NTTIME",
"NTTIME_hyper" => "NTTIME",
"WERROR" => "WERROR",
"NTSTATUS" => "NTSTATUS",
"HRESULT" => "HRESULT",
"COMRESULT" => "COMRESULT",
"dns_string" => "const char *",
"nbt_string" => "const char *",
"wrepl_nbt_name"=> "struct nbt_name *",
"ipv4address" => "const char *",
"ipv6address" => "const char *",
"dnsp_name" => "const char *",
"dnsp_string" => "const char *",
);
my %aliases = (
"error_status_t" => "uint32",
"boolean8" => "uint8",
"boolean32" => "uint32",
"DWORD" => "uint32",
"uint" => "uint32",
"int" => "int32",
"WORD" => "uint16",
"char" => "uint8",
"long" => "int32",
"short" => "int16",
"HYPER_T" => "hyper",
"mode_t" => "uint32",
);
sub expandAlias($)
{
my $name = shift;
return $aliases{$name} if defined($aliases{$name});
return $name;
}
# map from a IDL type to a C header type
sub mapScalarType($)
{
my $name = shift;
# it's a bug when a type is not in the list
# of known scalars or has no mapping
return $scalars{$name} if defined($scalars{$name});
die("Unknown scalar type $name");
}
sub maybeMapScalarType($)
{
my $name = shift;
return $scalars{$name} if defined($scalars{$name});
return $name;
}
sub addType($)
{
my $t = shift;
$types{$t->{NAME}} = $t;
}
sub resolveType($)
{
my ($ctype) = @_;
if (not hasType($ctype)) {
# assume struct typedef
return { TYPE => "TYPEDEF", NAME => $ctype, DATA => { TYPE => "STRUCT" } };
} else {
return getType($ctype);
}
return $ctype;
}
sub getType($)
{
my $t = shift;
return ($t) if (ref($t) eq "HASH" and not defined($t->{NAME}));
return undef if not hasType($t);
return $types{$t->{NAME}} if (ref($t) eq "HASH");
return $types{$t};
}
sub typeIs($$);
sub typeIs($$)
{
my ($t,$tt) = @_;
if (ref($t) eq "HASH") {
return 1 if ($t->{TYPE} eq "TYPEDEF" and $t->{DATA}->{TYPE} eq $tt);
return 1 if ($t->{TYPE} eq $tt);
return 0;
}
if (hasType($t) and getType($t)->{TYPE} eq "TYPEDEF") {
return typeIs(getType($t)->{DATA}, $tt);
}
return 0;
}
sub hasType($)
{
my $t = shift;
if (ref($t) eq "HASH") {
return 1 if (not defined($t->{NAME}));
return 1 if (defined($types{$t->{NAME}}) and
$types{$t->{NAME}}->{TYPE} eq $t->{TYPE});
return 0;
}
return 1 if defined($types{$t});
return 0;
}
sub is_signed($)
{
my $t = shift;
return ($t eq "int8"
or $t eq "int16"
or $t eq "int32"
or $t eq "dlong"
or $t eq "int"
or $t eq "long"
or $t eq "short");
}
sub is_scalar($)
{
sub is_scalar($);
my $type = shift;
return 1 if (ref($type) eq "HASH" and
($type->{TYPE} eq "SCALAR" or $type->{TYPE} eq "ENUM" or
$type->{TYPE} eq "BITMAP"));
if (my $dt = getType($type)) {
return is_scalar($dt->{DATA}) if ($dt->{TYPE} eq "TYPEDEF");
return 1 if ($dt->{TYPE} eq "SCALAR" or $dt->{TYPE} eq "ENUM" or
$dt->{TYPE} eq "BITMAP");
}
return 0;
}
sub is_struct($)
{
my $type = shift;
return 1 if (ref($type) eq "HASH" and $type->{TYPE} eq "STRUCT");
if (my $dt = getType($type)) {
return is_struct($dt->{DATA}) if ($dt->{TYPE} eq "TYPEDEF");
return 1 if ($dt->{TYPE} eq "STRUCT");
}
return 0;
}
sub is_fixed_size_scalar($)
{
my $name = shift;
return 0 unless is_scalar($name);
return 0 if (grep(/^$name$/, @non_fixed_size_scalars));
return 1;
}
sub scalar_is_reference($)
{
my $name = shift;
return 1 if (grep(/^$name$/, @reference_scalars));
return 0;
}
sub RegisterScalars()
{
foreach (keys %scalars) {
addType({
NAME => $_,
TYPE => "TYPEDEF",
BASEFILE => "<builtin>",
DATA => {
TYPE => "SCALAR",
NAME => $_
}
}
);
}
}
sub enum_type_fn($)
{
my $enum = shift;
$enum->{TYPE} eq "ENUM" or die("not an enum");
# for typedef enum { } we need to check $enum->{PARENT}
if (has_property($enum, "enum8bit")) {
return "uint8";
} elsif (has_property($enum, "enum16bit")) {
return "uint16";
} elsif (has_property($enum, "v1_enum")) {
return "uint32";
} elsif (has_property($enum->{PARENT}, "enum8bit")) {
return "uint8";
} elsif (has_property($enum->{PARENT}, "enum16bit")) {
return "uint16";
} elsif (has_property($enum->{PARENT}, "v1_enum")) {
return "uint32";
}
return "uint1632";
}
sub bitmap_type_fn($)
{
my $bitmap = shift;
$bitmap->{TYPE} eq "BITMAP" or die("not a bitmap");
if (has_property($bitmap, "bitmap8bit")) {
return "uint8";
} elsif (has_property($bitmap, "bitmap16bit")) {
return "uint16";
} elsif (has_property($bitmap, "bitmap64bit")) {
return "hyper";
}
return "uint32";
}
sub typeHasBody($)
{
sub typeHasBody($);
my ($e) = @_;
if ($e->{TYPE} eq "TYPEDEF") {
return 0 unless(defined($e->{DATA}));
return typeHasBody($e->{DATA});
}
return defined($e->{ELEMENTS});
}
sub mapType($$)
{
sub mapType($$);
my ($t, $n) = @_;
return mapTypeName($t->{DATA}) if ($t->{TYPE} eq "TYPEDEF");
return mapScalarType($n) if ($t->{TYPE} eq "SCALAR");
return "enum $n" if ($t->{TYPE} eq "ENUM");
return "struct $n" if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "INTERFACE");
return "union $n" if ($t->{TYPE} eq "UNION");
return mapScalarType(bitmap_type_fn($t)) if ($t->{TYPE} eq "BITMAP");
return "struct $n" if ($t->{TYPE} eq "PIPE");
die("Unknown type $t->{TYPE}");
}
sub mapTypeName($)
{
my $t = shift;
return "void" unless defined($t);
my $dt;
$t = expandAlias($t);
if ($dt = getType($t)) {
return mapType($dt, $dt->{NAME});
} elsif (ref($t) eq "HASH" and defined($t->{NAME})) {
return mapType($t, $t->{NAME});
} else {
# Best guess
return "struct $t";
}
}
sub LoadIdl($;$)
{
my $idl = shift;
my $basename = shift;
foreach my $x (@{$idl}) {
next if $x->{TYPE} ne "INTERFACE";
# DCOM interfaces can be types as well
addType({
NAME => $x->{NAME},
TYPE => "TYPEDEF",
DATA => $x,
BASEFILE => $basename,
}) if (has_property($x, "object"));
foreach my $y (@{$x->{DATA}}) {
if ($y->{TYPE} eq "TYPEDEF"
or $y->{TYPE} eq "UNION"
or $y->{TYPE} eq "STRUCT"
or $y->{TYPE} eq "ENUM"
or $y->{TYPE} eq "BITMAP"
or $y->{TYPE} eq "PIPE") {
$y->{BASEFILE} = $basename;
addType($y);
}
}
}
}
sub GenerateTypeLib()
{
return Parse::Pidl::Util::MyDumper(\%types);
}
RegisterScalars();
1;

View File

@ -0,0 +1,182 @@
###################################################
# utility functions to support pidl
# Copyright tridge@samba.org 2000
# released under the GNU GPL
package Parse::Pidl::Util;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(has_property property_matches ParseExpr ParseExprExt is_constant make_str unmake_str print_uuid MyDumper);
use vars qw($VERSION);
$VERSION = '0.01';
use strict;
use Parse::Pidl::Expr;
use Parse::Pidl qw(error);
=head1 NAME
Parse::Pidl::Util - Generic utility functions for pidl
=head1 SYNOPSIS
use Parse::Pidl::Util;
=head1 DESCRIPTION
Simple module that contains a couple of trivial helper functions
used throughout the various pidl modules.
=head1 FUNCTIONS
=over 4
=cut
=item B<MyDumper>
a dumper wrapper to prevent dependence on the Data::Dumper module
unless we actually need it
=cut
sub MyDumper($)
{
require Data::Dumper;
my $s = shift;
return Data::Dumper::Dumper($s);
}
=item B<has_property>
see if a pidl property list contains a given property
=cut
sub has_property($$)
{
my($e, $p) = @_;
return undef if (not defined($e->{PROPERTIES}));
return $e->{PROPERTIES}->{$p};
}
=item B<property_matches>
see if a pidl property matches a value
=cut
sub property_matches($$$)
{
my($e,$p,$v) = @_;
if (!defined has_property($e, $p)) {
return undef;
}
if ($e->{PROPERTIES}->{$p} =~ /$v/) {
return 1;
}
return undef;
}
=item B<is_constant>
return 1 if the string is a C constant
=cut
sub is_constant($)
{
my $s = shift;
return 1 if ($s =~ /^\d+$/);
return 1 if ($s =~ /^0x[0-9A-Fa-f]+$/);
return 0;
}
=item B<make_str>
return a "" quoted string, unless already quoted
=cut
sub make_str($)
{
my $str = shift;
if (substr($str, 0, 1) eq "\"") {
return $str;
}
return "\"$str\"";
}
=item B<unmake_str>
unquote a "" quoted string
=cut
sub unmake_str($)
{
my $str = shift;
$str =~ s/^\"(.*)\"$/$1/;
return $str;
}
=item B<print_uuid>
Print C representation of a UUID.
=cut
sub print_uuid($)
{
my ($uuid) = @_;
$uuid =~ s/"//g;
my ($time_low,$time_mid,$time_hi,$clock_seq,$node) = split /-/, $uuid;
return undef if not defined($node);
my @clock_seq = $clock_seq =~ /(..)/g;
my @node = $node =~ /(..)/g;
return "{0x$time_low,0x$time_mid,0x$time_hi," .
"{".join(',', map {"0x$_"} @clock_seq)."}," .
"{".join(',', map {"0x$_"} @node)."}}";
}
=item B<ParseExpr>
Interpret an IDL expression, substituting particular variables.
=cut
sub ParseExpr($$$)
{
my($expr, $varlist, $e) = @_;
my $x = new Parse::Pidl::Expr();
return $x->Run($expr, sub { my $x = shift; error($e, $x); },
# Lookup fn
sub { my $x = shift;
return($varlist->{$x}) if (defined($varlist->{$x}));
return $x;
},
undef, undef);
}
=item B<ParseExprExt>
Interpret an IDL expression, substituting particular variables. Can call
callbacks when pointers are being dereferenced or variables are being used.
=cut
sub ParseExprExt($$$$$)
{
my($expr, $varlist, $e, $deref, $use) = @_;
my $x = new Parse::Pidl::Expr();
return $x->Run($expr, sub { my $x = shift; error($e, $x); },
# Lookup fn
sub { my $x = shift;
return($varlist->{$x}) if (defined($varlist->{$x}));
return $x;
},
$deref, $use);
}
=back
=cut
1;

View File

@ -0,0 +1,451 @@
###################################################
# parse an Wireshark conformance file
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
=pod
=head1 NAME
Parse::Pidl::Wireshark::Conformance - Conformance file parser for Wireshark
=head1 DESCRIPTION
This module supports parsing Wireshark conformance files (*.cnf).
=head1 FILE FORMAT
Pidl needs additional data for Wireshark output. This data is read from
so-called conformance files. This section describes the format of these
files.
Conformance files are simple text files with a single command on each line.
Empty lines and lines starting with a '#' character are ignored.
Arguments to commands are seperated by spaces.
The following commands are currently supported:
=over 4
=item I<TYPE> name dissector ft_type base_type mask valsstring alignment
Register new data type with specified name, what dissector function to call
and what properties to give header fields for elements of this type.
=item I<NOEMIT> type
Suppress emitting a dissect_type function for the specified type
=item I<PARAM_VALUE> type param
Set parameter to specify to dissector function for given type.
=item I<HF_FIELD> hf title filter ft_type base_type valsstring mask description
Generate a custom header field with specified properties.
=item I<HF_RENAME> old_hf_name new_hf_name
Force the use of new_hf_name when the parser generator was going to
use old_hf_name.
This can be used in conjunction with HF_FIELD in order to make more than
one element use the same filter name.
=item I<ETT_FIELD> ett
Register a custom ett field
=item I<STRIP_PREFIX> prefix
Remove the specified prefix from all function names (if present).
=item I<PROTOCOL> longname shortname filtername
Change the short-, long- and filter-name for the current interface in
Wireshark.
=item I<FIELD_DESCRIPTION> field desc
Change description for the specified header field. `field' is the hf name of the field.
=item I<IMPORT> dissector code...
Code to insert when generating the specified dissector. @HF@ and
@PARAM@ will be substituted.
=item I<INCLUDE> filename
Include conformance data from the specified filename in the dissector.
=item I<TFS> hf_name "true string" "false string"
Override the text shown when a bitmap boolean value is enabled or disabled.
=item I<MANUAL> fn_name
Force pidl to not generate a particular function but allow the user
to write a function manually. This can be used to remove the function
for only one level for a particular element rather than all the functions and
ett/hf variables for a particular element as the NOEMIT command does.
=back
=head1 EXAMPLE
INFO_KEY OpenKey.Ke
=cut
package Parse::Pidl::Wireshark::Conformance;
require Exporter;
use vars qw($VERSION);
$VERSION = '0.01';
@ISA = qw(Exporter);
@EXPORT_OK = qw(ReadConformance ReadConformanceFH valid_ft_type valid_base_type);
use strict;
use Parse::Pidl qw(fatal warning error);
use Parse::Pidl::Util qw(has_property);
use Parse::Pidl::Typelist qw(addType);
sub handle_type($$$$$$$$$$)
{
my ($pos,$data,$name,$dissectorname,$ft_type,$base_type,$mask,$valsstring,$alignment) = @_;
unless(defined($alignment)) {
error($pos, "incomplete TYPE command");
return;
}
unless ($dissectorname =~ /.*dissect_.*/) {
warning($pos, "dissector name does not contain `dissect'");
}
unless(valid_ft_type($ft_type)) {
warning($pos, "invalid FT_TYPE `$ft_type'");
}
unless (valid_base_type($base_type)) {
warning($pos, "invalid BASE_TYPE `$base_type'");
}
$dissectorname =~ s/^\"(.*)\"$/$1/g;
if (not ($dissectorname =~ /;$/)) {
warning($pos, "missing semicolon");
}
$data->{types}->{$name} = {
NAME => $name,
POS => $pos,
USED => 0,
DISSECTOR_NAME => $dissectorname,
FT_TYPE => $ft_type,
BASE_TYPE => $base_type,
MASK => $mask,
VALSSTRING => $valsstring,
ALIGNMENT => $alignment
};
addType({
NAME => $name,
TYPE => "CONFORMANCE",
BASEFILE => "conformance file",
DATA => {
NAME => $name,
TYPE => "CONFORMANCE",
ALIGN => $alignment
}
});
}
sub handle_tfs($$$$$)
{
my ($pos,$data,$hf,$trues,$falses) = @_;
unless(defined($falses)) {
error($pos, "incomplete TFS command");
return;
}
$data->{tfs}->{$hf} = {
TRUE_STRING => $trues,
FALSE_STRING => $falses
};
}
sub handle_hf_rename($$$$)
{
my ($pos,$data,$old,$new) = @_;
unless(defined($new)) {
warning($pos, "incomplete HF_RENAME command");
return;
}
$data->{hf_renames}->{$old} = {
OLDNAME => $old,
NEWNAME => $new,
POS => $pos,
USED => 0
};
}
sub handle_param_value($$$$)
{
my ($pos,$data,$dissector_name,$value) = @_;
unless(defined($value)) {
error($pos, "incomplete PARAM_VALUE command");
return;
}
$data->{dissectorparams}->{$dissector_name} = {
DISSECTOR => $dissector_name,
PARAM => $value,
POS => $pos,
USED => 0
};
}
sub valid_base_type($)
{
my $t = shift;
return 0 unless($t =~ /^BASE_.*/);
return 1;
}
sub valid_ft_type($)
{
my $t = shift;
return 0 unless($t =~ /^FT_.*/);
return 1;
}
sub handle_hf_field($$$$$$$$$$)
{
my ($pos,$data,$index,$name,$filter,$ft_type,$base_type,$valsstring,$mask,$blurb) = @_;
unless(defined($blurb)) {
error($pos, "incomplete HF_FIELD command");
return;
}
unless(valid_ft_type($ft_type)) {
warning($pos, "invalid FT_TYPE `$ft_type'");
}
unless(valid_base_type($base_type)) {
warning($pos, "invalid BASE_TYPE `$base_type'");
}
$data->{header_fields}->{$index} = {
INDEX => $index,
POS => $pos,
USED => 0,
NAME => $name,
FILTER => $filter,
FT_TYPE => $ft_type,
BASE_TYPE => $base_type,
VALSSTRING => $valsstring,
MASK => $mask,
BLURB => $blurb
};
}
sub handle_strip_prefix($$$)
{
my ($pos,$data,$x) = @_;
push (@{$data->{strip_prefixes}}, $x);
}
sub handle_noemit($$$)
{
my ($pos,$data,$type) = @_;
if (defined($type)) {
$data->{noemit}->{$type} = 1;
} else {
$data->{noemit_dissector} = 1;
}
}
sub handle_manual($$$)
{
my ($pos,$data,$fn) = @_;
unless(defined($fn)) {
warning($pos, "incomplete MANUAL command");
return;
}
$data->{manual}->{$fn} = 1;
}
sub handle_protocol($$$$$$)
{
my ($pos, $data, $name, $longname, $shortname, $filtername) = @_;
$data->{protocols}->{$name} = {
LONGNAME => $longname,
SHORTNAME => $shortname,
FILTERNAME => $filtername
};
}
sub handle_fielddescription($$$$)
{
my ($pos,$data,$field,$desc) = @_;
unless(defined($desc)) {
warning($pos, "incomplete FIELD_DESCRIPTION command");
return;
}
$data->{fielddescription}->{$field} = {
DESCRIPTION => $desc,
POS => $pos,
USED => 0
};
}
sub handle_import
{
my $pos = shift @_;
my $data = shift @_;
my $dissectorname = shift @_;
unless(defined($dissectorname)) {
error($pos, "no dissectorname specified");
return;
}
$data->{imports}->{$dissectorname} = {
NAME => $dissectorname,
DATA => join(' ', @_),
USED => 0,
POS => $pos
};
}
sub handle_ett_field
{
my $pos = shift @_;
my $data = shift @_;
my $ett = shift @_;
unless(defined($ett)) {
error($pos, "incomplete ETT_FIELD command");
return;
}
push (@{$data->{ett}}, $ett);
}
sub handle_include
{
my $pos = shift @_;
my $data = shift @_;
my $fn = shift @_;
unless(defined($fn)) {
error($pos, "incomplete INCLUDE command");
return;
}
ReadConformance($fn, $data);
}
my %field_handlers = (
TYPE => \&handle_type,
NOEMIT => \&handle_noemit,
MANUAL => \&handle_manual,
PARAM_VALUE => \&handle_param_value,
HF_FIELD => \&handle_hf_field,
HF_RENAME => \&handle_hf_rename,
ETT_FIELD => \&handle_ett_field,
TFS => \&handle_tfs,
STRIP_PREFIX => \&handle_strip_prefix,
PROTOCOL => \&handle_protocol,
FIELD_DESCRIPTION => \&handle_fielddescription,
IMPORT => \&handle_import,
INCLUDE => \&handle_include
);
sub ReadConformance($$)
{
my ($f,$data) = @_;
my $ret;
open(IN,"<$f") or return undef;
$ret = ReadConformanceFH(*IN, $data, $f);
close(IN);
return $ret;
}
sub ReadConformanceFH($$$)
{
my ($fh,$data,$f) = @_;
my $incodeblock = 0;
my $ln = 0;
foreach (<$fh>) {
$ln++;
next if (/^#.*$/);
next if (/^$/);
s/[\r\n]//g;
if ($_ eq "CODE START") {
$incodeblock = 1;
next;
} elsif ($incodeblock and $_ eq "CODE END") {
$incodeblock = 0;
next;
} elsif ($incodeblock) {
if (exists $data->{override}) {
$data->{override}.="$_\n";
} else {
$data->{override} = "$_\n";
}
next;
}
my @fields = /([^ "]+|"[^"]+")/g;
my $cmd = $fields[0];
shift @fields;
my $pos = { FILE => $f, LINE => $ln };
next unless(defined($cmd));
if (not defined($field_handlers{$cmd})) {
warning($pos, "Unknown command `$cmd'");
next;
}
$field_handlers{$cmd}($pos, $data, @fields);
}
if ($incodeblock) {
warning({ FILE => $f, LINE => $ln },
"Expecting CODE END");
return undef;
}
return 1;
}
1;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,471 @@
#
# Module Parse::Yapp::Driver
#
# This module is part of the Parse::Yapp package available on your
# nearest CPAN
#
# Any use of this module in a standalone parser make the included
# text under the same copyright as the Parse::Yapp module itself.
#
# This notice should remain unchanged.
#
# (c) Copyright 1998-2001 Francois Desarmenien, all rights reserved.
# (see the pod text in Parse::Yapp module for use and distribution rights)
#
package Parse::Yapp::Driver;
require 5.004;
use strict;
use vars qw ( $VERSION $COMPATIBLE $FILENAME );
$VERSION = '1.05';
$COMPATIBLE = '0.07';
$FILENAME=__FILE__;
use Carp;
#Known parameters, all starting with YY (leading YY will be discarded)
my(%params)=(YYLEX => 'CODE', 'YYERROR' => 'CODE', YYVERSION => '',
YYRULES => 'ARRAY', YYSTATES => 'ARRAY', YYDEBUG => '');
#Mandatory parameters
my(@params)=('LEX','RULES','STATES');
sub new {
my($class)=shift;
my($errst,$nberr,$token,$value,$check,$dotpos);
my($self)={ ERROR => \&_Error,
ERRST => \$errst,
NBERR => \$nberr,
TOKEN => \$token,
VALUE => \$value,
DOTPOS => \$dotpos,
STACK => [],
DEBUG => 0,
CHECK => \$check };
_CheckParams( [], \%params, \@_, $self );
exists($$self{VERSION})
and $$self{VERSION} < $COMPATIBLE
and croak "Yapp driver version $VERSION ".
"incompatible with version $$self{VERSION}:\n".
"Please recompile parser module.";
ref($class)
and $class=ref($class);
bless($self,$class);
}
sub YYParse {
my($self)=shift;
my($retval);
_CheckParams( \@params, \%params, \@_, $self );
if($$self{DEBUG}) {
_DBLoad();
$retval = eval '$self->_DBParse()';#Do not create stab entry on compile
$@ and die $@;
}
else {
$retval = $self->_Parse();
}
$retval
}
sub YYData {
my($self)=shift;
exists($$self{USER})
or $$self{USER}={};
$$self{USER};
}
sub YYErrok {
my($self)=shift;
${$$self{ERRST}}=0;
undef;
}
sub YYNberr {
my($self)=shift;
${$$self{NBERR}};
}
sub YYRecovering {
my($self)=shift;
${$$self{ERRST}} != 0;
}
sub YYAbort {
my($self)=shift;
${$$self{CHECK}}='ABORT';
undef;
}
sub YYAccept {
my($self)=shift;
${$$self{CHECK}}='ACCEPT';
undef;
}
sub YYError {
my($self)=shift;
${$$self{CHECK}}='ERROR';
undef;
}
sub YYSemval {
my($self)=shift;
my($index)= $_[0] - ${$$self{DOTPOS}} - 1;
$index < 0
and -$index <= @{$$self{STACK}}
and return $$self{STACK}[$index][1];
undef; #Invalid index
}
sub YYCurtok {
my($self)=shift;
@_
and ${$$self{TOKEN}}=$_[0];
${$$self{TOKEN}};
}
sub YYCurval {
my($self)=shift;
@_
and ${$$self{VALUE}}=$_[0];
${$$self{VALUE}};
}
sub YYExpect {
my($self)=shift;
keys %{$self->{STATES}[$self->{STACK}[-1][0]]{ACTIONS}}
}
sub YYLexer {
my($self)=shift;
$$self{LEX};
}
#################
# Private stuff #
#################
sub _CheckParams {
my($mandatory,$checklist,$inarray,$outhash)=@_;
my($prm,$value);
my($prmlst)={};
while(($prm,$value)=splice(@$inarray,0,2)) {
$prm=uc($prm);
exists($$checklist{$prm})
or croak("Unknow parameter '$prm'");
ref($value) eq $$checklist{$prm}
or croak("Invalid value for parameter '$prm'");
$prm=unpack('@2A*',$prm);
$$outhash{$prm}=$value;
}
for (@$mandatory) {
exists($$outhash{$_})
or croak("Missing mandatory parameter '".lc($_)."'");
}
}
sub _Error {
print "Parse error.\n";
}
sub _DBLoad {
{
no strict 'refs';
exists(${__PACKAGE__.'::'}{_DBParse})#Already loaded ?
and return;
}
my($fname)=__FILE__;
my(@drv);
open(DRV,"<$fname") or die "Report this as a BUG: Cannot open $fname";
while(<DRV>) {
/^\s*sub\s+_Parse\s*{\s*$/ .. /^\s*}\s*#\s*_Parse\s*$/
and do {
s/^#DBG>//;
push(@drv,$_);
}
}
close(DRV);
$drv[0]=~s/_P/_DBP/;
eval join('',@drv);
}
#Note that for loading debugging version of the driver,
#this file will be parsed from 'sub _Parse' up to '}#_Parse' inclusive.
#So, DO NOT remove comment at end of sub !!!
sub _Parse {
my($self)=shift;
my($rules,$states,$lex,$error)
= @$self{ 'RULES', 'STATES', 'LEX', 'ERROR' };
my($errstatus,$nberror,$token,$value,$stack,$check,$dotpos)
= @$self{ 'ERRST', 'NBERR', 'TOKEN', 'VALUE', 'STACK', 'CHECK', 'DOTPOS' };
#DBG> my($debug)=$$self{DEBUG};
#DBG> my($dbgerror)=0;
#DBG> my($ShowCurToken) = sub {
#DBG> my($tok)='>';
#DBG> for (split('',$$token)) {
#DBG> $tok.= (ord($_) < 32 or ord($_) > 126)
#DBG> ? sprintf('<%02X>',ord($_))
#DBG> : $_;
#DBG> }
#DBG> $tok.='<';
#DBG> };
$$errstatus=0;
$$nberror=0;
($$token,$$value)=(undef,undef);
@$stack=( [ 0, undef ] );
$$check='';
while(1) {
my($actions,$act,$stateno);
$stateno=$$stack[-1][0];
$actions=$$states[$stateno];
#DBG> print STDERR ('-' x 40),"\n";
#DBG> $debug & 0x2
#DBG> and print STDERR "In state $stateno:\n";
#DBG> $debug & 0x08
#DBG> and print STDERR "Stack:[".
#DBG> join(',',map { $$_[0] } @$stack).
#DBG> "]\n";
if (exists($$actions{ACTIONS})) {
defined($$token)
or do {
($$token,$$value)=&$lex($self);
#DBG> $debug & 0x01
#DBG> and print STDERR "Need token. Got ".&$ShowCurToken."\n";
};
$act= exists($$actions{ACTIONS}{$$token})
? $$actions{ACTIONS}{$$token}
: exists($$actions{DEFAULT})
? $$actions{DEFAULT}
: undef;
}
else {
$act=$$actions{DEFAULT};
#DBG> $debug & 0x01
#DBG> and print STDERR "Don't need token.\n";
}
defined($act)
and do {
$act > 0
and do { #shift
#DBG> $debug & 0x04
#DBG> and print STDERR "Shift and go to state $act.\n";
$$errstatus
and do {
--$$errstatus;
#DBG> $debug & 0x10
#DBG> and $dbgerror
#DBG> and $$errstatus == 0
#DBG> and do {
#DBG> print STDERR "**End of Error recovery.\n";
#DBG> $dbgerror=0;
#DBG> };
};
push(@$stack,[ $act, $$value ]);
$$token ne '' #Don't eat the eof
and $$token=$$value=undef;
next;
};
#reduce
my($lhs,$len,$code,@sempar,$semval);
($lhs,$len,$code)=@{$$rules[-$act]};
#DBG> $debug & 0x04
#DBG> and $act
#DBG> and print STDERR "Reduce using rule ".-$act." ($lhs,$len): ";
$act
or $self->YYAccept();
$$dotpos=$len;
unpack('A1',$lhs) eq '@' #In line rule
and do {
$lhs =~ /^\@[0-9]+\-([0-9]+)$/
or die "In line rule name '$lhs' ill formed: ".
"report it as a BUG.\n";
$$dotpos = $1;
};
@sempar = $$dotpos
? map { $$_[1] } @$stack[ -$$dotpos .. -1 ]
: ();
$semval = $code ? &$code( $self, @sempar )
: @sempar ? $sempar[0] : undef;
splice(@$stack,-$len,$len);
$$check eq 'ACCEPT'
and do {
#DBG> $debug & 0x04
#DBG> and print STDERR "Accept.\n";
return($semval);
};
$$check eq 'ABORT'
and do {
#DBG> $debug & 0x04
#DBG> and print STDERR "Abort.\n";
return(undef);
};
#DBG> $debug & 0x04
#DBG> and print STDERR "Back to state $$stack[-1][0], then ";
$$check eq 'ERROR'
or do {
#DBG> $debug & 0x04
#DBG> and print STDERR
#DBG> "go to state $$states[$$stack[-1][0]]{GOTOS}{$lhs}.\n";
#DBG> $debug & 0x10
#DBG> and $dbgerror
#DBG> and $$errstatus == 0
#DBG> and do {
#DBG> print STDERR "**End of Error recovery.\n";
#DBG> $dbgerror=0;
#DBG> };
push(@$stack,
[ $$states[$$stack[-1][0]]{GOTOS}{$lhs}, $semval ]);
$$check='';
next;
};
#DBG> $debug & 0x04
#DBG> and print STDERR "Forced Error recovery.\n";
$$check='';
};
#Error
$$errstatus
or do {
$$errstatus = 1;
&$error($self);
$$errstatus # if 0, then YYErrok has been called
or next; # so continue parsing
#DBG> $debug & 0x10
#DBG> and do {
#DBG> print STDERR "**Entering Error recovery.\n";
#DBG> ++$dbgerror;
#DBG> };
++$$nberror;
};
$$errstatus == 3 #The next token is not valid: discard it
and do {
$$token eq '' # End of input: no hope
and do {
#DBG> $debug & 0x10
#DBG> and print STDERR "**At eof: aborting.\n";
return(undef);
};
#DBG> $debug & 0x10
#DBG> and print STDERR "**Dicard invalid token ".&$ShowCurToken.".\n";
$$token=$$value=undef;
};
$$errstatus=3;
while( @$stack
and ( not exists($$states[$$stack[-1][0]]{ACTIONS})
or not exists($$states[$$stack[-1][0]]{ACTIONS}{error})
or $$states[$$stack[-1][0]]{ACTIONS}{error} <= 0)) {
#DBG> $debug & 0x10
#DBG> and print STDERR "**Pop state $$stack[-1][0].\n";
pop(@$stack);
}
@$stack
or do {
#DBG> $debug & 0x10
#DBG> and print STDERR "**No state left on stack: aborting.\n";
return(undef);
};
#shift the error token
#DBG> $debug & 0x10
#DBG> and print STDERR "**Shift \$error token and go to state ".
#DBG> $$states[$$stack[-1][0]]{ACTIONS}{error}.
#DBG> ".\n";
push(@$stack, [ $$states[$$stack[-1][0]]{ACTIONS}{error}, undef ]);
}
#never reached
croak("Error in driver logic. Please, report it as a BUG");
}#_Parse
#DO NOT remove comment
1;

View File

@ -0,0 +1,4 @@
#!/usr/bin/env python
# install the pidl modules
bld.INSTALL_WILDCARD('${DATAROOTDIR}/perl5', '**/*.pm', flat=False)

839
tools/pidl/pidl Executable file
View File

@ -0,0 +1,839 @@
#!/usr/bin/env perl
###################################################
# package to parse IDL files and generate code for
# rpc functions in Samba
# Copyright tridge@samba.org 2000-2003
# Copyright jelmer@samba.org 2005-2007
# released under the GNU GPL
# Modifications for COMROGUE - Copyright erbo@erbosoft.com 2013
=pod
=head1 NAME
pidl - An IDL compiler written in Perl
=head1 SYNOPSIS
pidl --help
pidl [--outputdir[=OUTNAME]] [--includedir DIR...] [--parse-idl-tree] [--dump-idl-tree] [--dump-ndr-tree] [--header[=OUTPUT]] [--python[=OUTPUT]] [--ndr-parser[=OUTPUT]] [--client] [--server] [--warn-compat] [--quiet] [--verbose] [--template] [--ws-parser[=OUTPUT]] [--diff] [--dump-idl] [--tdr-parser[=OUTPUT]] [--samba3-ndr-client[=OUTPUT]] [--samba3-ndr-server[=OUTPUT]] [--typelib=[OUTPUT]] [--comrogue-header=[OUTPUT]] [<idlfile>.idl]...
=head1 DESCRIPTION
pidl is an IDL compiler written in Perl that aims to be somewhat
compatible with the midl compiler. IDL is short for
"Interface Definition Language".
pidl can generate stubs for DCE/RPC server code, DCE/RPC
client code and Wireshark dissectors for DCE/RPC traffic.
IDL compilers like pidl take a description
of an interface as their input and use it to generate C
(though support for other languages may be added later) code that
can use these interfaces, pretty print data sent
using these interfaces, or even generate Wireshark
dissectors that can parse data sent over the
wire by these interfaces.
pidl takes IDL files in the same format as is used by midl,
converts it to a .pidl file (which contains pidl's internal representation of the interface) and can then generate whatever output you need.
.pidl files should be used for debugging purposes only. Write your
interface definitions in .idl format.
The goal of pidl is to implement a IDL compiler that can be used
while developing the RPC subsystem in Samba (for
both marshalling/unmarshalling and debugging purposes).
For COMROGUE, pidl generates the header files for interfaces.
=head1 OPTIONS
=over 4
=item I<--help>
Show list of available options.
=item I<--version>
Show pidl version
=item I<--outputdir OUTNAME>
Write output files to the specified directory. Defaults to the current
directory.
=item I<--includedir DIR>
Add DIR to the search path used by the preprocessor. This option can be
specified multiple times.
=item I<--parse-idl-tree>
Read internal tree structure from input files rather
than assuming they contain IDL.
=item I<--dump-idl>
Generate a new IDL file. File will be named OUTNAME.idl.
=item I<--header>
Generate a C header file for the specified interface. Filename defaults to OUTNAME.h.
=item I<--ndr-parser>
Generate a C file and C header containing NDR parsers. The filename for
the parser defaults to ndr_OUTNAME.c. The header filename will be the
parser filename with the extension changed from .c to .h.
=item I<--tdr-parser>
Generate a C file and C header containing TDR parsers. The filename for
the parser defaults to tdr_OUTNAME.c. The header filename will be the
parser filename with the extension changed from .c to .h.
=item I<--typelib>
Write type information to the specified file.
=item I<--server>
Generate boilerplate for the RPC server that implements
the interface. Filename defaults to ndr_OUTNAME_s.c.
=item I<--template>
Generate stubs for a RPC server that implements the interface. Output will
be written to stdout.
=item I<--ws-parser>
Generate an Wireshark dissector (in C) and header file. The dissector filename
defaults to packet-dcerpc-OUTNAME.c while the header filename defaults to
packet-dcerpc-OUTNAME.h.
Pidl will read additional data from an Wireshark conformance file if present.
Such a file should have the same location as the IDL file but with the
extension I<cnf> rather than I<idl>. See L<Parse::Pidl::Wireshark::Conformance>
for details on the format of this file.
=item I<--diff>
Parse an IDL file, generate a new IDL file based on the internal data
structures and see if there are any differences with the original IDL file.
Useful for debugging pidl.
=item I<--dump-idl-tree>
Tell pidl to dump the internal tree representation of an IDL
file the to disk. Useful for debugging pidl.
=item I<--dump-ndr-tree>
Tell pidl to dump the internal NDR information tree it generated
from the IDL file to disk. Useful for debugging pidl.
=item I<--samba3-ndr-client>
Generate client calls for Samba3, to be placed in rpc_client/. Instead of
calling out to the code in Samba3's rpc_parse/, this will call out to
Samba4's NDR code instead.
=item I<--samba3-ndr-server>
Generate server calls for Samba3, to be placed in rpc_server/. Instead of
calling out to the code in Samba3's rpc_parse/, this will call out to
Samba4's NDR code instead.
=item I<--comrogue-header>
Generate interface header files for COMROGUE. Filename defaults to
OUTNAME.h.
=back
=head1 IDL SYNTAX
IDL files are always preprocessed using the C preprocessor.
Pretty much everything in an interface (the interface itself, functions,
parameters) can have attributes (or properties whatever name you give them).
Attributes always prepend the element they apply to and are surrounded
by square brackets ([]). Multiple attributes are separated by comma's;
arguments to attributes are specified between parentheses.
See the section COMPATIBILITY for the list of attributes that
pidl supports.
C-style comments can be used.
=head2 CONFORMANT ARRAYS
A conformant array is one with that ends in [*] or []. The strange
things about conformant arrays are that they can only appear as the last
element of a structure (unless there is a pointer to the conformant array,
of course) and the array size appears before the structure itself on the wire.
So, in this example:
typedef struct {
long abc;
long count;
long foo;
[size_is(count)] long s[*];
} Struct1;
it appears like this:
[size_is] [abc] [count] [foo] [s...]
the first [size_is] field is the allocation size of the array, and
occurs before the array elements and even before the structure
alignment.
Note that size_is() can refer to a constant, but that doesn't change
the wire representation. It does not make the array a fixed array.
midl.exe would write the above array as the following C header:
typedef struct {
long abc;
long count;
long foo;
long s[1];
} Struct1;
pidl takes a different approach, and writes it like this:
typedef struct {
long abc;
long count;
long foo;
long *s;
} Struct1;
=head2 VARYING ARRAYS
A varying array looks like this:
typedef struct {
long abc;
long count;
long foo;
[size_is(count)] long *s;
} Struct1;
This will look like this on the wire:
[abc] [count] [foo] [PTR_s] [count] [s...]
=head2 FIXED ARRAYS
A fixed array looks like this:
typedef struct {
long s[10];
} Struct1;
The NDR representation looks just like 10 separate long
declarations. The array size is not encoded on the wire.
pidl also supports "inline" arrays, which are not part of the IDL/NDR
standard. These are declared like this:
typedef struct {
uint32 foo;
uint32 count;
uint32 bar;
long s[count];
} Struct1;
This appears like this:
[foo] [count] [bar] [s...]
Fixed arrays are an extension added to support some of the strange
embedded structures in security descriptors and spoolss.
This section is by no means complete. See the OpenGroup and MSDN
documentation for additional information.
=head1 COMPATIBILITY WITH MIDL
=head2 Missing features in pidl
The following MIDL features are not (yet) implemented in pidl
or are implemented with an incompatible interface:
=over
=item *
Asynchronous communication
=item *
Typelibs (.tlb files)
=item *
Datagram support (ncadg_*)
=back
=head2 Supported attributes and statements
in, out, ref, length_is, switch_is, size_is, uuid, case, default, string,
unique, ptr, pointer_default, v1_enum, object, helpstring, range, local,
call_as, endpoint, switch_type, progid, coclass, iid_is, represent_as,
transmit_as, import, include, cpp_quote.
=head2 PIDL Specific properties
=over 4
=item public
The [public] property on a structure or union is a pidl extension that
forces the generated pull/push functions to be non-static. This allows
you to declare types that can be used between modules. If you don't
specify [public] then pull/push functions for other than top-level
functions are declared static.
=item noprint
The [noprint] property is a pidl extension that allows you to specify
that pidl should not generate a ndr_print_*() function for that
structure or union. This is used when you wish to define your own
print function that prints a structure in a nicer manner. A good
example is the use of [noprint] on dom_sid, which allows the
pretty-printing of SIDs.
=item value
The [value(expression)] property is a pidl extension that allows you
to specify the value of a field when it is put on the wire. This
allows fields that always have a well-known value to be automatically
filled in, thus making the API more programmer friendly. The
expression can be any C expression.
=item relative
The [relative] property can be supplied on a pointer. When it is used
it declares the pointer as a spoolss style "relative" pointer, which
means it appears on the wire as an offset within the current
encapsulating structure. This is not part of normal IDL/NDR, but it is
a very useful extension as it avoids the manual encoding of many
complex structures.
=item subcontext(length)
Specifies that a size of I<length>
bytes should be read, followed by a blob of that size,
which will be parsed as NDR.
subcontext() is deprecated now, and should not be used in new code.
Instead, use represent_as() or transmit_as().
=item flag
Specify boolean options, mostly used for
low-level NDR options. Several options
can be specified using the | character.
Note that flags are inherited by substructures!
=item nodiscriminant
The [nodiscriminant] property on a union means that the usual uint16
discriminent field at the start of the union on the wire is
omitted. This is not normally allowed in IDL/NDR, but is used for some
spoolss structures.
=item charset(name)
Specify that the array or string uses the specified
charset. If this attribute is specified, pidl will
take care of converting the character data from this format
to the host format. Commonly used values are UCS2, DOS and UTF8.
=back
=head2 Unsupported MIDL properties or statements
aggregatable, appobject, async_uuid, bindable, control,
defaultbind, defaultcollelem, defaultvalue, defaultvtable, dispinterface,
displaybind, dual, entry, first_is, helpcontext, helpfile, helpstringcontext,
helpstringdll, hidden, idl_module, idl_quote, id, immediatebind, importlib,
includelib, last_is, lcid, licensed, max_is, module,
ms_union, no_injected_text, nonbrowsable, noncreatable, nonextensible, odl,
oleautomation, optional, pragma, propget, propputref, propput, readonly,
requestedit, restricted, retval, source, uidefault,
usesgetlasterror, vararg, vi_progid, wire_marshal.
=head1 EXAMPLES
# Generating an Wireshark parser
$ ./pidl --ws-parser -- atsvc.idl
# Generating a TDR parser and header
$ ./pidl --tdr-parser --header -- regf.idl
# Generating a Samba3 client and server
$ ./pidl --samba3-ndr-client --samba3-ndr-server -- dfs.idl
# Generating a Samba4 NDR parser, client and server
$ ./pidl --ndr-parser --ndr-client --ndr-server -- samr.idl
=head1 SEE ALSO
L<http://msdn.microsoft.com/library/en-us/rpc/rpc/field_attributes.asp>,
L<http://wiki.wireshark.org/DCE/RPC>,
L<http://www.samba.org/>,
L<yapp(1)>
=head1 LICENSE
pidl is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
=head1 AUTHOR
pidl was written by Andrew Tridgell, Stefan Metzmacher, Tim Potter and Jelmer
Vernooij. The current maintainer is Jelmer Vernooij.
This manpage was written by Jelmer Vernooij, partially based on the original
pidl README by Andrew Tridgell.
This code has been modified for use with the COMROGUE operating system by Eric J. Bowersox.
=cut
use strict;
use FindBin qw($RealBin $Script);
use lib "$RealBin/lib";
use lib "$RealBin/../share/perl5";
use Getopt::Long;
use File::Basename;
use Parse::Pidl qw ( $VERSION );
use Parse::Pidl::Util;
use Parse::Pidl::ODL;
#####################################################################
# save a data structure into a file
sub SaveStructure($$)
{
my($filename,$v) = @_;
FileSave($filename, Parse::Pidl::Util::MyDumper($v));
}
#####################################################################
# load a data structure from a file (as saved with SaveStructure)
sub LoadStructure($)
{
my $f = shift;
my $contents = FileLoad($f);
defined $contents || return undef;
return eval "$contents";
}
#####################################################################
# read a file into a string
sub FileLoad($)
{
my($filename) = shift;
local(*INPUTFILE);
open(INPUTFILE, $filename) || return undef;
my($saved_delim) = $/;
undef $/;
my($data) = <INPUTFILE>;
close(INPUTFILE);
$/ = $saved_delim;
return $data;
}
#####################################################################
# write a string into a file
sub FileSave($$)
{
my($filename) = shift;
my($v) = shift;
local(*FILE);
open(FILE, ">$filename") || die "can't open $filename";
print FILE $v;
close(FILE);
}
my(@opt_incdirs) = ();
my($opt_help) = 0;
my($opt_version) = 0;
my($opt_parse_idl_tree) = 0;
my($opt_dump_idl_tree);
my($opt_dump_ndr_tree);
my($opt_dump_idl) = 0;
my($opt_diff) = 0;
my($opt_header);
my($opt_samba3_header);
my($opt_samba3_parser);
my($opt_samba3_server);
my($opt_samba3_ndr_client);
my($opt_samba3_ndr_server);
my($opt_template) = 0;
my($opt_client);
my($opt_typelib);
my($opt_server);
my($opt_ndr_parser);
my($opt_tdr_parser);
my($opt_ws_parser);
my($opt_python);
my($opt_quiet) = 0;
my($opt_outputdir) = '.';
my($opt_verbose) = 0;
my($opt_warn_compat) = 0;
my($opt_dcom_proxy);
my($opt_com_header);
my($opt_comrogue_header);
#########################################
# display help text
sub ShowHelp()
{
print "perl IDL parser and code generator\n";
ShowVersion();
print"
Copyright (C) Andrew Tridgell <tridge\@samba.org>
Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
Usage: $Script [options] [--] <idlfile> [<idlfile>...]
Generic Options:
--help this help page
--version show pidl version
--outputdir=OUTDIR put output in OUTDIR/ [.]
--warn-compat warn about incompatibility with other compilers
--quiet be quiet
--verbose be verbose
--includedir DIR search DIR for included files
Debugging:
--dump-idl-tree[=FILE] dump internal representation to file [BASENAME.pidl]
--parse-idl-tree read internal representation instead of IDL
--dump-ndr-tree[=FILE] dump internal NDR data tree to file [BASENAME.ndr]
--dump-idl regenerate IDL file
--diff run diff on original IDL and dumped output
--typelib print type information
Samba 4 output:
--header[=OUTFILE] create generic header file [BASENAME.h]
--ndr-parser[=OUTFILE] create a C NDR parser [ndr_BASENAME.c]
--client[=OUTFILE] create a C NDR client [ndr_BASENAME_c.c]
--tdr-parser[=OUTFILE] create a C TDR parser [tdr_BASENAME.c]
--python[=OUTFILE] create python wrapper file [py_BASENAME.c]
--server[=OUTFILE] create server boilerplate [ndr_BASENAME_s.c]
--template print a template for a pipe
--dcom-proxy[=OUTFILE] create DCOM proxy [ndr_BASENAME_p.c]
--com-header[=OUTFILE] create header for COM [com_BASENAME.h]
Samba 3 output:
--samba3-ndr-client[=OUTF] create client calls for Samba3
using Samba4's NDR code [cli_BASENAME.c]
--samba3-ndr-server[=OUTF] create server call wrapper for Samba3
using Samba4's NDR code [srv_BASENAME.c]
Wireshark parsers:
--ws-parser[=OUTFILE] create Wireshark parser and header
COMROGUE:
--comrogue-header[=OUTFILE] create header for COMROGUE interface
[BASENAME.h]
\n";
exit(0);
}
#########################################
# Display version
sub ShowVersion()
{
print "perl IDL version $VERSION\n";
}
# main program
my $result = GetOptions (
'help|h|?' => \$opt_help,
'version' => \$opt_version,
'outputdir=s' => \$opt_outputdir,
'dump-idl' => \$opt_dump_idl,
'dump-idl-tree:s' => \$opt_dump_idl_tree,
'parse-idl-tree' => \$opt_parse_idl_tree,
'dump-ndr-tree:s' => \$opt_dump_ndr_tree,
'samba3-ndr-client:s' => \$opt_samba3_ndr_client,
'samba3-ndr-server:s' => \$opt_samba3_ndr_server,
'header:s' => \$opt_header,
'server:s' => \$opt_server,
'typelib:s' => \$opt_typelib,
'tdr-parser:s' => \$opt_tdr_parser,
'template' => \$opt_template,
'ndr-parser:s' => \$opt_ndr_parser,
'client:s' => \$opt_client,
'ws-parser:s' => \$opt_ws_parser,
'python' => \$opt_python,
'diff' => \$opt_diff,
'dcom-proxy:s' => \$opt_dcom_proxy,
'com-header:s' => \$opt_com_header,
'comrogue-header:s' => \$opt_comrogue_header,
'quiet' => \$opt_quiet,
'verbose' => \$opt_verbose,
'warn-compat' => \$opt_warn_compat,
'includedir=s@' => \@opt_incdirs
);
if (not $result) {
exit(1);
}
if ($opt_help) {
ShowHelp();
exit(0);
}
if ($opt_version) {
ShowVersion();
exit(0);
}
sub process_imports($)
{
my $pidl = shift;
foreach my $d (@{$pidl})
{
next unless $d->{TYPE} eq "IMPORT";
foreach my $p (@{$d->{PATHS}}) {
my $f = Parse::Pidl::IDL::parse_file($p, \@opt_incdirs);
defined @$f || die "Failed to parse $p";
my $basename = basename($p, ".idl");
Parse::Pidl::Typelist::LoadIdl($f, $basename);
process_imports($f);
}
}
}
sub process_file($)
{
my $idl_file = shift;
my $outputdir = $opt_outputdir;
my $pidl;
my $ndr;
my $basename = basename($idl_file, ".idl");
unless ($opt_quiet) { print "Compiling $idl_file\n"; }
if ($opt_parse_idl_tree) {
$pidl = LoadStructure($idl_file);
defined $pidl || die "Failed to load $idl_file";
} else {
require Parse::Pidl::IDL;
$pidl = Parse::Pidl::IDL::parse_file($idl_file, \@opt_incdirs);
defined @$pidl || die "Failed to parse $idl_file";
}
require Parse::Pidl::Typelist;
Parse::Pidl::Typelist::LoadIdl($pidl, $basename);
if (defined($opt_dump_idl_tree)) {
my($pidl_file) = ($opt_dump_idl_tree or "$outputdir/$basename.pidl");
SaveStructure($pidl_file, $pidl) or die "Failed to save $pidl_file\n";
}
if ($opt_dump_idl) {
require Parse::Pidl::Dump;
print Parse::Pidl::Dump($pidl);
}
if ($opt_diff) {
my($tempfile) = "$outputdir/$basename.tmp";
FileSave($tempfile, IdlDump::Dump($pidl));
system("diff -wu $idl_file $tempfile");
unlink($tempfile);
}
my $crh_filename = ($opt_comrogue_header or "$outputdir/$basename.h");
if (defined($opt_comrogue_header)) {
process_imports($pidl);
require Parse::Pidl::COMROGUE::Header;
my $res = Parse::Pidl::COMROGUE::Header::Parse($pidl,$basename,$idl_file);
if ($res) {
FileSave($crh_filename, $res);
}
}
my $comh_filename = ($opt_com_header or "$outputdir/com_$basename.h");
if (defined($opt_com_header)) {
require Parse::Pidl::Samba4::COM::Header;
my $res = Parse::Pidl::Samba4::COM::Header::Parse($pidl,"$outputdir/ndr_$basename.h");
if ($res) {
FileSave($comh_filename, $res);
}
}
if (defined($opt_dcom_proxy)) {
require Parse::Pidl::Samba4::COM::Proxy;
my $res = Parse::Pidl::Samba4::COM::Proxy::Parse($pidl,$comh_filename);
if ($res) {
my ($client) = ($opt_dcom_proxy or "$outputdir/$basename\_p.c");
FileSave($client, $res);
}
}
if ($opt_warn_compat) {
require Parse::Pidl::Compat;
Parse::Pidl::Compat::Check($pidl);
}
$pidl = Parse::Pidl::ODL::ODL2IDL($pidl, dirname($idl_file), \@opt_incdirs);
if (defined($opt_ws_parser)) {
require Parse::Pidl::Wireshark::NDR;
my $cnffile = $idl_file;
$cnffile =~ s/\.idl$/\.cnf/;
my $generator = new Parse::Pidl::Wireshark::NDR();
$generator->Initialize($cnffile);
}
if (defined($opt_ws_parser) or
defined($opt_client) or
defined($opt_server) or
defined($opt_header) or
defined($opt_ndr_parser) or
defined($opt_python) or
defined($opt_dump_ndr_tree) or
defined($opt_samba3_header) or
defined($opt_samba3_parser) or
defined($opt_samba3_server) or
defined($opt_samba3_ndr_client) or
defined($opt_samba3_ndr_server)) {
require Parse::Pidl::NDR;
$ndr = Parse::Pidl::NDR::Parse($pidl);
}
if (defined($opt_dump_ndr_tree)) {
my($ndr_file) = ($opt_dump_ndr_tree or "$outputdir/$basename.ndr");
SaveStructure($ndr_file, $ndr) or die "Failed to save $ndr_file\n";
}
my $gen_header = ($opt_header or "$outputdir/$basename.h");
if (defined($opt_header)) {
require Parse::Pidl::Samba4::Header;
FileSave($gen_header, Parse::Pidl::Samba4::Header::Parse($ndr));
}
my $h_filename = "$outputdir/ndr_$basename.h";
my $c_header = "$outputdir/ndr_$basename\_c.h";
if (defined($opt_client) or defined($opt_samba3_ndr_client)) {
require Parse::Pidl::Samba4::NDR::Client;
my ($c_client) = ($opt_client or "$outputdir/ndr_$basename\_c.c");
$c_header = $c_client;
$c_header =~ s/\.c$/.h/;
my $generator = new Parse::Pidl::Samba4::NDR::Client();
my ($srcd,$hdrd) = $generator->Parse(
$ndr,$gen_header,$h_filename,$c_header);
FileSave($c_client, $srcd);
FileSave($c_header, $hdrd);
}
if (defined($opt_python)) {
require Parse::Pidl::Samba4::Python;
my $generator = new Parse::Pidl::Samba4::Python();
my ($prsr) = $generator->Parse($basename, $ndr,
"$outputdir/ndr_$basename\_c.h", $h_filename);
FileSave("$outputdir/py_$basename.c", $prsr);
}
if (defined($opt_server)) {
require Parse::Pidl::Samba4::NDR::Server;
FileSave(($opt_server or "$outputdir/ndr_$basename\_s.c"), Parse::Pidl::Samba4::NDR::Server::Parse($ndr,$h_filename));
}
if (defined($opt_ndr_parser)) {
my $parser_fname = ($opt_ndr_parser or "$outputdir/ndr_$basename.c");
require Parse::Pidl::Samba4::NDR::Parser;
my $generator = new Parse::Pidl::Samba4::NDR::Parser();
my ($header,$parser) = $generator->Parse($ndr, $gen_header, $h_filename);
FileSave($parser_fname, $parser);
FileSave($h_filename, $header);
}
if (defined($opt_ws_parser)) {
require Parse::Pidl::Wireshark::NDR;
my($eparser) = ($opt_ws_parser or "$outputdir/packet-dcerpc-$basename.c");
my $eheader = $eparser;
$eheader =~ s/\.c$/\.h/;
my $cnffile = $idl_file;
$cnffile =~ s/\.idl$/\.cnf/;
my $generator = new Parse::Pidl::Wireshark::NDR();
my ($dp, $dh) = $generator->Parse($ndr, $idl_file, $eheader, $cnffile);
FileSave($eparser, $dp) if defined($dp);
FileSave($eheader, $dh) if defined($dh);
}
if (defined($opt_tdr_parser)) {
my $tdr_parser = ($opt_tdr_parser or "$outputdir/tdr_$basename.c");
my $tdr_header = $tdr_parser;
$tdr_header =~ s/\.c$/\.h/;
require Parse::Pidl::Samba4::TDR;
my $generator = new Parse::Pidl::Samba4::TDR();
my ($hdr,$prsr) = $generator->Parser($pidl, $tdr_header, $gen_header);
FileSave($tdr_parser, $prsr);
FileSave($tdr_header, $hdr);
}
if (defined($opt_typelib)) {
my $typelib = ($opt_typelib or "$outputdir/$basename.tlb");
require Parse::Pidl::Typelist;
FileSave($typelib, Parse::Pidl::Typelist::GenerateTypeLib());
}
if ($opt_template) {
require Parse::Pidl::Samba4::Template;
print Parse::Pidl::Samba4::Template::Parse($pidl);
}
if (defined($opt_samba3_ndr_client)) {
my $client = ($opt_samba3_ndr_client or "$outputdir/cli_$basename.c");
my $header = $client; $header =~ s/\.c$/\.h/;
require Parse::Pidl::Samba3::ClientNDR;
my $generator = new Parse::Pidl::Samba3::ClientNDR();
my ($c_code,$h_code) = $generator->Parse($ndr, $header, $c_header);
FileSave($client, $c_code);
FileSave($header, $h_code);
}
if (defined($opt_samba3_ndr_server)) {
my $server = ($opt_samba3_ndr_server or "$outputdir/srv_$basename.c");
my $header = $server; $header =~ s/\.c$/\.h/;
require Parse::Pidl::Samba3::ServerNDR;
my ($c_code,$h_code) = Parse::Pidl::Samba3::ServerNDR::Parse($ndr, $header, $h_filename);
FileSave($server, $c_code);
FileSave($header, $h_code);
}
}
if (scalar(@ARGV) == 0) {
print "$Script: no input files\n";
exit(1);
}
process_file($_) foreach (@ARGV);

181
tools/pidl/tests/Util.pm Normal file
View File

@ -0,0 +1,181 @@
# Some simple utility functions for pidl tests
# Copyright (C) 2005-2006 Jelmer Vernooij
# Published under the GNU General Public License
package Util;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(test_samba4_ndr test_warnings test_errors);
use strict;
use FindBin qw($RealBin);
use lib "$RealBin/../lib";
use Parse::Pidl::Samba4 qw(is_intree);
use Parse::Pidl;
my $warnings = "";
undef &Parse::Pidl::warning;
*Parse::Pidl::warning = sub {
my ($e, $l) = @_;
if (defined($e)) {
$warnings .= "$e->{FILE}:$e->{LINE}: $l\n";
} else {
$warnings .= "$l\n";
}
};
my $errors = "";
undef &Parse::Pidl::error;
*Parse::Pidl::error = sub {
my ($e, $l) = @_;
if (defined($e)) {
$errors .= "$e->{FILE}:$e->{LINE}: $l\n";
} else {
$errors .= "$l\n";
}
};
use Test::More;
use Parse::Pidl::IDL;
use Parse::Pidl::NDR;
use Parse::Pidl::Samba4::NDR::Parser;
use Parse::Pidl::Samba4::Header;
# Generate a Samba4 parser for an IDL fragment and run it with a specified
# piece of code to check whether the parser works as expected
sub test_samba4_ndr
{
my ($name,$idl,$c,$extra) = @_;
$extra = "" unless defined($extra);
my $pidl = Parse::Pidl::IDL::parse_string("interface echo { $idl }; ", "<$name>");
ok(defined($pidl), "($name) parse idl");
my $pndr = Parse::Pidl::NDR::Parse($pidl);
ok(defined($pndr), "($name) generate NDR tree");
my $header = Parse::Pidl::Samba4::Header::Parse($pndr);
ok(defined($header), "($name) generate generic header");
my $generator = new Parse::Pidl::Samba4::NDR::Parser();
my ($ndrheader,$ndrparser) = $generator->Parse($pndr, undef, undef);
ok(defined($ndrparser), "($name) generate NDR parser");
ok(defined($ndrheader), "($name) generate NDR header");
SKIP: {
my $flags;
if (system("pkg-config --exists ndr") == 0 and !is_intree()) {
$flags = `pkg-config --libs --cflags ndr`;
} else {
skip "no samba environment available, skipping compilation", 3;
}
my $main = "
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <util/data_blob.h>
/* header start */
$header
/* header end */
/* ndrheader start */
$ndrheader
/* ndrheader end */
/* extra start */
$extra
/* extra end */
/* ndrparser start */
$ndrparser
/* ndrparser end */
/* main start */
int main(int argc, const char **argv)
{
TALLOC_CTX *mem_ctx = talloc_init(NULL);
$c
talloc_free(mem_ctx);
return 0;
}
/* main end */
\n";
my $main_debug = "# ".join("\n# ", split("\n", $main));
my $test_data_prefix = $ENV{TEST_DATA_PREFIX};
my $outfile;
if (defined($test_data_prefix)) {
$outfile = "$test_data_prefix/test-$name";
} else {
$outfile = "./test-$name";
}
my $cflags = $ENV{CFLAGS};
unless (defined($cflags)) {
$cflags = "";
}
my $ldflags = $ENV{LDFLAGS};
unless (defined($ldflags)) {
$ldflags = "";
}
my $cc = $ENV{CC};
unless (defined($cc)) {
$cc = "cc";
}
my $cmd = "$cc $cflags -x c - -o $outfile $flags $ldflags";
$cmd =~ s/\n//g;
open CC, "|$cmd";
print CC $main;
close CC;
ok(-f $outfile, "($name) compile");
my $ret = system($outfile, ()) >> 8;
print "# code:\n#\n$main_debug\n" if ($ret != 0);
print "# cmd: $cmd\n" if ($ret != 0);
print "# return code: $ret\n" if ($ret != 0);
ok($ret == 0, "($name) run");
ok(unlink($outfile), "($name) remove");
}
}
sub test_warnings($$)
{
my ($exp, $code) = @_;
$warnings = "";
$code->();
is($warnings, $exp);
}
sub test_errors($$)
{
my ($exp, $code) = @_;
$errors = "";
$code->();
is($errors, $exp);
}
1;

21
tools/pidl/tests/cutil.pl Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
# (C) 2007 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use warnings;
use Test::More tests => 7;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util;
use Parse::Pidl::Util qw(MyDumper);
use Parse::Pidl::CUtil qw(get_pointer_to get_value_of);
is("&foo", get_pointer_to("foo"));
is("&(&foo)", get_pointer_to(get_pointer_to("foo")));
is("*foo", get_pointer_to("**foo"));
is("foo", get_pointer_to("*foo"));
is("foo", get_value_of("&foo"));
is("*foo", get_value_of("foo"));
is("**foo", get_value_of("*foo"));

15
tools/pidl/tests/dump.pl Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/perl
# (C) 2007 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use warnings;
use Test::More tests => 1;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util;
use Parse::Pidl::Dump qw(DumpStruct);
is (DumpStruct({ NAME => "foo", ELEMENTS => []}),
"struct foo {\n}");

108
tools/pidl/tests/header.pl Executable file
View File

@ -0,0 +1,108 @@
#!/usr/bin/perl
# (C) 2007 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use warnings;
use Test::More tests => 27;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util;
use Parse::Pidl::Util qw(MyDumper);
use Parse::Pidl::Samba4::Header qw(
GenerateFunctionInEnv GenerateFunctionOutEnv GenerateStructEnv
EnvSubstituteValue);
use Parse::Pidl::IDL qw(parse_string);
use Parse::Pidl::NDR;
sub parse_idl($)
{
my $text = shift;
my $idl = Parse::Pidl::IDL::parse_string($text, "nofile");
my $ndr = Parse::Pidl::NDR::Parse($idl);
return Parse::Pidl::Samba4::Header::Parse($ndr);
}
like(parse_idl(""), qr/\/\* header auto-generated by pidl \*\/\n/sm, "includes work");
like(parse_idl("interface x {}"), qr/\/\* header auto-generated by pidl \*\/\n/sm, "simple empty interface doesn't cause overhead");
like(parse_idl("interface p { typedef struct { int y; } x; };"),
qr/.*#ifndef _HEADER_p\n#define _HEADER_p\n.+\n#endif \/\* _HEADER_p \*\/.*/ms, "ifdefs are created");
like(parse_idl("interface p { typedef struct { int y; } x; };"),
qr/struct x.*{.*int32_t y;.*}.*;/sm, "interface member generated properly");
like(parse_idl("interface x { void foo (void); };"),
qr/struct foo.*{\s+int _dummy_element;\s+};/sm, "void fn contains dummy element");
like(parse_idl("interface x { void foo ([in] uint32 x); };"),
qr/struct foo.*{\s+struct\s+{\s+uint32_t x;\s+} in;\s+};/sm, "fn in arg works");
like(parse_idl("interface x { void foo ([out] uint32 x); };"),
qr/struct foo.*{.*struct\s+{\s+uint32_t x;\s+} out;.*};/sm, "fn out arg works");
like(parse_idl("interface x { void foo ([in,out] uint32 x); };"),
qr/struct foo.*{.*struct\s+{\s+uint32_t x;\s+} in;\s+struct\s+{\s+uint32_t x;\s+} out;.*};/sm, "fn in,out arg works");
like(parse_idl("interface x { void foo (uint32 x); };"), qr/struct foo.*{.*struct\s+{\s+uint32_t x;\s+} in;\s+struct\s+{\s+uint32_t x;\s+} out;.*};/sm, "fn with no props implies in,out");
like(parse_idl("interface p { struct x { int y; }; };"),
qr/struct x.*{.*int32_t y;.*}.*;/sm, "interface member generated properly");
like(parse_idl("interface p { struct x { struct y z; }; };"),
qr/struct x.*{.*struct y z;.*}.*;/sm, "tagged type struct member");
like(parse_idl("interface p { struct x { union y z; }; };"),
qr/struct x.*{.*union y z;.*}.*;/sm, "tagged type union member");
like(parse_idl("interface p { struct x { }; };"),
qr/struct x.*{.*char _empty_;.*}.*;/sm, "empty struct");
like(parse_idl("interface p { struct x; };"),
qr/struct x;/sm, "struct declaration");
like(parse_idl("interface p { typedef struct x { int p; } x; };"),
qr/struct x.*{.*int32_t p;.*};/sm, "double struct declaration");
like(parse_idl("cpp_quote(\"some-foo\")"),
qr/some-foo/sm, "cpp quote");
# Make sure GenerateFunctionInEnv and GenerateFunctionOutEnv work
my $fn = { ELEMENTS => [ { DIRECTION => ["in"], NAME => "foo" } ] };
is_deeply({ "foo" => "r->in.foo" }, GenerateFunctionInEnv($fn));
$fn = { ELEMENTS => [ { DIRECTION => ["out"], NAME => "foo" } ] };
is_deeply({ "foo" => "r->out.foo" }, GenerateFunctionOutEnv($fn));
$fn = { ELEMENTS => [ { DIRECTION => ["out", "in"], NAME => "foo" } ] };
is_deeply({ "foo" => "r->in.foo" }, GenerateFunctionInEnv($fn));
$fn = { ELEMENTS => [ { DIRECTION => ["out", "in"], NAME => "foo" } ] };
is_deeply({ "foo" => "r->out.foo" }, GenerateFunctionOutEnv($fn));
$fn = { ELEMENTS => [ { DIRECTION => ["in"], NAME => "foo" } ] };
is_deeply({ "foo" => "r->in.foo" }, GenerateFunctionOutEnv($fn));
$fn = { ELEMENTS => [ { DIRECTION => ["out"], NAME => "foo" } ] };
is_deeply({ }, GenerateFunctionInEnv($fn));
$fn = { ELEMENTS => [ { NAME => "foo" }, { NAME => "bar" } ] };
is_deeply({ foo => "r->foo", bar => "r->bar", this => "r" },
GenerateStructEnv($fn, "r"));
$fn = { ELEMENTS => [ { NAME => "foo" }, { NAME => "bar" } ] };
is_deeply({ foo => "some->complex.variable->foo",
bar => "some->complex.variable->bar",
this => "some->complex.variable" },
GenerateStructEnv($fn, "some->complex.variable"));
$fn = { ELEMENTS => [ { NAME => "foo", PROPERTIES => { value => 3 }} ] };
my $env = GenerateStructEnv($fn, "r");
EnvSubstituteValue($env, $fn);
is_deeply($env, { foo => 3, this => "r" });
$fn = { ELEMENTS => [ { NAME => "foo" }, { NAME => "bar" } ] };
$env = GenerateStructEnv($fn, "r");
EnvSubstituteValue($env, $fn);
is_deeply($env, { foo => 'r->foo', bar => 'r->bar', this => "r" });
$fn = { ELEMENTS => [ { NAME => "foo", PROPERTIES => { value => 0 }} ] };
$env = GenerateStructEnv($fn, "r");
EnvSubstituteValue($env, $fn);
is_deeply($env, { foo => 0, this => "r" });

561
tools/pidl/tests/ndr.pl Executable file
View File

@ -0,0 +1,561 @@
#!/usr/bin/perl
# (C) 2007 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use warnings;
use Test::More tests => 47;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util;
use Parse::Pidl::Util qw(MyDumper);
use Parse::Pidl::NDR qw(GetElementLevelTable ParseElement align_type mapToScalar ParseType can_contain_deferred);
# Case 1
my $e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {},
'POINTERS' => 0,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
'IS_DEFERRED' => 0,
'LEVEL_INDEX' => 0,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
my $ne = ParseElement($e, "unique", 0);
is($ne->{ORIGINAL}, $e);
is($ne->{NAME}, "v");
is($ne->{ALIGN}, 1);
is($ne->{TYPE}, "uint8");
is_deeply($ne->{LEVELS}, [
{
'IS_DEFERRED' => 0,
'LEVEL_INDEX' => 0,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 2 : pointers
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"unique" => 1},
'POINTERS' => 1,
'PARENT' => { TYPE => 'STRUCT' },
'TYPE' => 'uint8',
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 0,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 1,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 3 : double pointers
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"unique" => 1},
'POINTERS' => 2,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 0,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 1,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 1,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 2,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 3 : ref pointers
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"ref" => 1},
'POINTERS' => 1,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 0,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 1,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 3 : ref pointers
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"ref" => 1},
'POINTERS' => 3,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 0,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 1,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 1,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 2,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 2,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 3,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 3 : ref pointers
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"ref" => 1},
'POINTERS' => 3,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "ref", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 0,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 1,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 1,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 2,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 2,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 3,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 4 : top-level ref pointers
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"ref" => 1},
'POINTERS' => 1,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'FUNCTION' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 0,
LEVEL => 'TOP'
},
{
'IS_DEFERRED' => 0,
'LEVEL_INDEX' => 1,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 4 : top-level ref pointers, triple with pointer_default("unique")
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"ref" => 1},
'POINTERS' => 3,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'FUNCTION' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 0,
LEVEL => 'TOP'
},
{
LEVEL_INDEX => 1,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 1,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 2,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 2,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 3,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 4 : top-level unique pointers, triple with pointer_default("unique")
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"unique" => 1, "in" => 1},
'POINTERS' => 3,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'FUNCTION' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "unique", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 0,
LEVEL => 'TOP'
},
{
LEVEL_INDEX => 1,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 1,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 2,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 2,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 3,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 4 : top-level unique pointers, triple with pointer_default("ref")
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"unique" => 1, "in" => 1},
'POINTERS' => 3,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'FUNCTION' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "ref", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "unique",
POINTER_INDEX => 0,
LEVEL => 'TOP'
},
{
LEVEL_INDEX => 1,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 1,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 2,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 2,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 3,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# Case 4 : top-level ref pointers, triple with pointer_default("ref")
#
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"ref" => 1},
'POINTERS' => 3,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'FUNCTION' },
'LINE' => 42 };
is_deeply(GetElementLevelTable($e, "ref", 0), [
{
LEVEL_INDEX => 0,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 0,
LEVEL => 'TOP'
},
{
LEVEL_INDEX => 1,
IS_DEFERRED => 0,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 1,
LEVEL => 'EMBEDDED'
},
{
LEVEL_INDEX => 2,
IS_DEFERRED => 1,
TYPE => 'POINTER',
POINTER_TYPE => "ref",
POINTER_INDEX => 2,
LEVEL => 'EMBEDDED'
},
{
'IS_DEFERRED' => 1,
'LEVEL_INDEX' => 3,
'DATA_TYPE' => 'uint8',
'CONTAINS_DEFERRED' => 0,
'TYPE' => 'DATA',
'IS_SURROUNDING' => 0,
}
]);
# representation_type
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => { represent_as => "bar" },
'POINTERS' => 0,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
$ne = ParseElement($e, undef, 0);
is($ne->{REPRESENTATION_TYPE}, "bar");
# representation_type
$e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => { },
'POINTERS' => 0,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
$ne = ParseElement($e, undef, 0);
is($ne->{REPRESENTATION_TYPE}, "uint8");
is(align_type("hyper"), 8);
is(align_type("double"), 8);
is(align_type("uint32"), 4);
is(align_type("uint16"), 2);
is(align_type("uint8"), 1);
is(align_type({ TYPE => "STRUCT", "NAME" => "bla",
ELEMENTS => [ { TYPE => "uint16" } ] }), 4);
is(align_type({ TYPE => "STRUCT",
ELEMENTS => [ { TYPE => "hyper" } ] }), 8);
is(align_type({ TYPE => "TYPEDEF", DATA => {
TYPE => "STRUCT",
ELEMENTS => [ { TYPE => "hyper" } ] }}), 8);
# typedef of struct without body
is(align_type({ TYPE => "TYPEDEF", DATA => {
TYPE => "STRUCT", ELEMENTS => undef }}), 4);
# struct without body
is(align_type({ TYPE => "STRUCT", ELEMENTS => undef }), 4);
# empty struct
is(align_type({ TYPE => "STRUCT", ELEMENTS => [] }), 1);
is(align_type({ TYPE => "STRUCT", "NAME" => "bla",
ELEMENTS => [ { TYPE => "uint8" } ] }), 4);
is(mapToScalar("someverymuchnotexistingtype"), undef);
is(mapToScalar("uint32"), "uint32");
is(mapToScalar({TYPE => "ENUM", PARENT => { PROPERTIES => { enum8bit => 1 } } }), "uint8");
is(mapToScalar({TYPE => "BITMAP", PROPERTIES => { bitmap64bit => 1 } }),
"hyper");
is(mapToScalar({TYPE => "TYPEDEF", DATA => {TYPE => "ENUM", PARENT => { PROPERTIES => { enum8bit => 1 } } }}), "uint8");
my $t;
$t = {
TYPE => "STRUCT",
NAME => "foo",
SURROUNDING_ELEMENT => undef,
ELEMENTS => undef,
PROPERTIES => undef,
ORIGINAL => {
TYPE => "STRUCT",
NAME => "foo"
},
ALIGN => undef
};
is_deeply(ParseType($t->{ORIGINAL}, "ref", 0), $t);
$t = {
TYPE => "UNION",
NAME => "foo",
SWITCH_TYPE => "uint32",
ELEMENTS => undef,
PROPERTIES => undef,
HAS_DEFAULT => 0,
IS_MS_UNION => 0,
ORIGINAL => {
TYPE => "UNION",
NAME => "foo"
},
ALIGN => undef
};
is_deeply(ParseType($t->{ORIGINAL}, "ref", 0), $t);
ok(not can_contain_deferred("uint32"));
ok(can_contain_deferred("some_unknown_type"));
ok(can_contain_deferred({ TYPE => "STRUCT",
ELEMENTS => [ { TYPE => "uint32", POINTERS => 40 } ]}));
ok(can_contain_deferred({ TYPE => "TYPEDEF",
DATA => { TYPE => "STRUCT",
ELEMENTS => [ { TYPE => "uint32", POINTERS => 40 } ]}}));
ok(not can_contain_deferred({ TYPE => "STRUCT",
ELEMENTS => [ { TYPE => "uint32" } ]}));
ok(not can_contain_deferred({ TYPE => "TYPEDEF",
DATA => { TYPE => "STRUCT",
ELEMENTS => [ { TYPE => "uint32" } ]}}));
ok(can_contain_deferred({ TYPE => "STRUCT",
ELEMENTS => [ { TYPE => "someunknowntype" } ]}));
# Make sure the elements for a enum without body aren't filled in
ok(not defined(ParseType({TYPE => "ENUM", NAME => "foo" }, "ref", 0)->{ELEMENTS}));
# Make sure the elements for a bitmap without body aren't filled in
ok(not defined(ParseType({TYPE => "BITMAP", NAME => "foo" }, "ref", 0)->{ELEMENTS}));
# Make sure the elements for a union without body aren't filled in
ok(not defined(ParseType({TYPE => "UNION", NAME => "foo" }, "ref", 0)->{ELEMENTS}));

143
tools/pidl/tests/ndr_align.pl Executable file
View File

@ -0,0 +1,143 @@
#!/usr/bin/perl
# NDR alignment tests
# (C) 2005 Jelmer Vernooij. Published under the GNU GPL
use strict;
use Test::More tests => 5 * 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
test_samba4_ndr('align-uint8-uint16',
'
typedef [public] struct {
uint8 x;
uint16 y;
} bla;
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct bla r;
uint8_t expected[] = { 0x0D, 0x00, 0xef, 0xbe };
DATA_BLOB expected_blob = { expected, 4 };
DATA_BLOB result_blob;
r.x = 13;
r.y = 0xbeef;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');
test_samba4_ndr('align-uint8-uint32',
'
typedef [public] struct {
uint8 x;
uint32 y;
} bla;
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct bla r;
uint8_t expected[] = { 0x0D, 0x00, 0x00, 0x00, 0xef, 0xbe, 0xef, 0xbe };
DATA_BLOB expected_blob = { expected, 8 };
DATA_BLOB result_blob;
r.x = 13;
r.y = 0xbeefbeef;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');
test_samba4_ndr('align-uint8-hyper',
'
typedef [public] struct {
uint8 x;
hyper y;
} bla;
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct bla r;
uint8_t expected[] = { 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe };
DATA_BLOB expected_blob = { expected, 16 };
DATA_BLOB result_blob;
r.x = 13;
r.y = 0xbeefbeefbeefbeefLLU;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');
test_samba4_ndr('noalignflag-uint8-uint16',
'
typedef [public] struct {
uint8 x;
uint16 y;
} bla;
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct bla r;
uint8_t expected[] = { 0x0D, 0xef, 0xbe };
DATA_BLOB expected_blob = { expected, 3 };
DATA_BLOB result_blob;
ndr->flags |= LIBNDR_FLAG_NOALIGN;
r.x = 13;
r.y = 0xbeef;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');
test_samba4_ndr('align-blob-align2',
'
typedef [public] struct {
uint8 x;
[flag(LIBNDR_FLAG_ALIGN2)] DATA_BLOB data;
uint8 y;
} blie;
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct blie r;
uint8_t data[] = { 0x01, 0x02 };
uint8_t expected[] = { 0x0D, 0x00, 0x0E };
DATA_BLOB expected_blob = { expected, 3 };
DATA_BLOB result_blob;
r.x = 13;
r.y = 14;
r.data.data = data;
r.data.length = 2;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_blie(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');

118
tools/pidl/tests/ndr_alloc.pl Executable file
View File

@ -0,0 +1,118 @@
#!/usr/bin/perl
# NDR allocation tests
# (C) 2005 Jelmer Vernooij. Published under the GNU GPL
use strict;
use Test::More tests => 5 * 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
# Check that an outgoing scalar pointer is allocated correctly
test_samba4_ndr("alloc-scalar",
'
typedef struct {
uint8 *x;
} bla;
[public] void TestAlloc([in] bla foo);
','
uint8_t data[] = { 0xde, 0xad, 0xbe, 0xef, 0x03 };
DATA_BLOB b = { data, 5 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct TestAlloc r;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
return 1;
if (r.in.foo.x == NULL)
return 2;
if (*r.in.foo.x != 0x03)
return 3;
'
);
# Check that an outgoing buffer pointer is allocated correctly
test_samba4_ndr("alloc-buffer",
'
typedef struct { uint8 data; } blie;
typedef struct { blie *x; } bla;
[public] void TestAlloc([in] bla foo);
','
uint8_t data[] = { 0xde, 0xad, 0xbe, 0xef, 0x03 };
DATA_BLOB b = { data, 5 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct TestAlloc r;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
return 1;
if (r.in.foo.x == NULL)
return 2;
if (r.in.foo.x->data != 0x03)
return 3;
'
);
# Check that ref pointers aren't allocated by default
test_samba4_ndr("ref-noalloc-null",
'
[public] void TestAlloc([in,ref] uint8 *t);
','
uint8_t data[] = { 0x03 };
DATA_BLOB b = { data, 1 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct TestAlloc r;
r.in.t = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
return 1;
'
);
# Check that ref pointers aren't allocated by default
test_samba4_ndr("ref-noalloc",
'
[public] void TestAlloc([in,ref] uint8 *t);
','
uint8_t data[] = { 0x03 };
DATA_BLOB b = { data, 1 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct TestAlloc r;
uint8_t x;
r.in.t = &x;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
return 1;
if (*r.in.t != 0x03)
return 2;
'
);
# Check that an outgoing ref pointer is allocated correctly
test_samba4_ndr("ref-alloc",
'
[public] void TestAlloc([in,ref] uint8 *t);
','
uint8_t data[] = { 0x03 };
DATA_BLOB b = { data, 1 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct TestAlloc r;
ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
r.in.t = NULL;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestAlloc(ndr, NDR_IN, &r)))
return 1;
if (r.in.t == NULL)
return 2;
if (*r.in.t != 0x03)
return 3;
'
);

37
tools/pidl/tests/ndr_array.pl Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/perl
# Array testing
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use Test::More tests => 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
test_samba4_ndr(
'Fixed-Array',
'[public] void Test([in] uint8 x[10]);',
'
uint8_t data[] = {1,2,3,4,5,6,7,8,9,10};
int i;
DATA_BLOB b;
struct ndr_pull *ndr;
struct Test r;
b.data = data;
b.length = 10;
ndr = ndr_pull_init_blob(&b, mem_ctx, NULL);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_Test(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 10)
return 2;
for (i = 0; i < 10; i++) {
if (r.in.x[i] != i+1) return 3;
}
');

21
tools/pidl/tests/ndr_compat.pl Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/perl
# (C) 2007 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use Test::More tests => 2;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util;
use Parse::Pidl;
use Parse::Pidl::IDL;
sub parse_idl($)
{
my $idl = shift;
my $pidl = Parse::Pidl::IDL::parse_string("interface echo { $idl }; ", "nofile");
Parse::Pidl::NDR::Parse($pidl);
}
test_warnings("", sub {parse_idl("void x();"); });
test_warnings("nofile:0: top-level [out] pointer `x' is not a [ref] pointer\n", sub {parse_idl("void x([out,unique] int *x);"); });

View File

@ -0,0 +1,26 @@
#!/usr/bin/perl
# (C) 2007 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use warnings;
use Test::More tests => 1;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util;
use Parse::Pidl::Util qw(MyDumper);
use Parse::Pidl::NDR qw(ValidElement);
# Case 1
my $e = {
'FILE' => 'foo.idl',
'NAME' => 'v',
'PROPERTIES' => {"subcontext" => 1},
'POINTERS' => 0,
'TYPE' => 'uint8',
'PARENT' => { TYPE => 'STRUCT' },
'LINE' => 42 };
test_warnings("foo.idl:42: subcontext() is deprecated. Use represent_as() or transmit_as() instead\n",
sub { ValidElement($e); });

44
tools/pidl/tests/ndr_fullptr.pl Executable file
View File

@ -0,0 +1,44 @@
#!/usr/bin/perl
# Simple tests for unique pointers
# (C) 2006 Jelmer Vernooij <jelmer@samba.org>.
# Published under the GNU General Public License.
use strict;
use Test::More tests => 1 * 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
SKIP: {
skip "full pointers not supported yet", 8;
test_samba4_ndr("fullptr-push-dup",
'
[public] uint16 echo_TestFull([in,ptr] uint32 *x, [in,ptr] uint32 *y);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
uint32_t v = 13;
struct echo_TestFull r;
r.in.x = &v;
r.in.y = &v;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestFull(ndr, NDR_IN, &r))) {
fprintf(stderr, "push failed\n");
return 1;
}
if (ndr->offset != 12) {
fprintf(stderr, "Offset(%d) != 12\n", ndr->offset);
return 2;
}
if (ndr->data[0] != ndr->data[8] ||
ndr->data[1] != ndr->data[9] ||
ndr->data[2] != ndr->data[10] ||
ndr->data[3] != ndr->data[11]) {
fprintf(stderr, "Data incorrect\n");
return 3;
}
');
}

526
tools/pidl/tests/ndr_refptr.pl Executable file
View File

@ -0,0 +1,526 @@
#!/usr/bin/perl
# Simple tests for pidl's handling of ref pointers, based
# on tridge's ref_notes.txt
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>.
# Published under the GNU General Public License.
use strict;
use Test::More tests => 22 * 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
test_samba4_ndr("noptr-push",
' typedef struct {
uint16 x;
} xstruct;
[public] uint16 echo_TestRef([in] xstruct foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
uint16_t v = 13;
struct echo_TestRef r;
r.in.foo.x = v;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r))) {
fprintf(stderr, "push failed\n");
return 1;
}
if (ndr->offset != 2) {
fprintf(stderr, "Offset(%d) != 2\n", ndr->offset);
return 2;
}
if (ndr->data[0] != 13 || ndr->data[1] != 0) {
fprintf(stderr, "Data incorrect\n");
return 3;
}
');
test_samba4_ndr("ptr-embedded-push",
' typedef struct {
uint16 *x;
} xstruct;
[public] uint16 echo_TestRef([in] xstruct foo);
',
'
uint16_t v = 13;
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo.x = &v;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 6)
return 2;
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
ndr->data[2] == 0 && ndr->data[3] == 0)
return 3;
if (ndr->data[4] != 13 || ndr->data[5] != 0)
return 4;
');
test_samba4_ndr("ptr-embedded-push-null",
' typedef struct {
uint16 *x;
} xstruct;
[public] uint16 echo_TestRef([in] xstruct foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo.x = NULL;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 4)
return 2;
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
ndr->data[2] != 0 || ndr->data[3] != 0)
return 3;
');
test_samba4_ndr("refptr-embedded-push",
'
typedef struct {
[ref] uint16 *x;
} xstruct;
[public] uint16 echo_TestRef([in] xstruct foo);
',
'
uint16_t v = 13;
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo.x = &v;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 6)
return 2;
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
ndr->data[2] == 0 && ndr->data[3] == 0)
return 3;
if (ndr->data[4] != 13 || ndr->data[5] != 0)
return 4;
');
test_samba4_ndr("refptr-embedded-push-null",
'
typedef struct {
[ref] uint16 *x;
} xstruct;
[public] uint16 echo_TestRef([in] xstruct foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo.x = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
/* Windows gives [client runtime error 0x6f4] */
');
test_samba4_ndr("ptr-top-push",
'
typedef struct {
uint16 x;
} xstruct;
[public] uint16 echo_TestRef([in] xstruct *foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
struct xstruct s;
s.x = 13;
r.in.foo = &s;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 2)
return 2;
if (ndr->data[0] != 13 || ndr->data[1] != 0)
return 3;
');
test_samba4_ndr("ptr-top-push-null",
'
typedef struct {
uint16 x;
} xstruct;
[public] uint16 echo_TestRef([in] xstruct *foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
/* Windows gives [client runtime error 0x6f4] */
');
test_samba4_ndr("refptr-top-push",
'
typedef struct {
uint16 x;
} xstruct;
[public] uint16 echo_TestRef([in,ref] xstruct *foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
struct xstruct s;
s.x = 13;
r.in.foo = &s;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 2)
return 2;
if (ndr->data[0] != 13 || ndr->data[1] != 0)
return 3;
');
test_samba4_ndr("refptr-top-push-null",
'
typedef struct {
uint16 x;
} xstruct;
[public] uint16 echo_TestRef([in,ref] xstruct *foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
/* Windows gives [client runtime error 0x6f4] */
');
test_samba4_ndr("uniqueptr-top-push",
' typedef struct {
uint16 x;
} xstruct;
[public] uint16 echo_TestRef([in,unique] xstruct *foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
struct xstruct s;
s.x = 13;
r.in.foo = &s;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 6)
return 2;
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
ndr->data[2] == 0 && ndr->data[3] == 0)
return 3;
if (ndr->data[4] != 13 || ndr->data[5] != 0)
return 4;
');
test_samba4_ndr("uniqueptr-top-push-null",
' typedef struct {
uint16 x;
} xstruct;
[public] uint16 echo_TestRef([in,unique] xstruct *foo);
',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo = NULL;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 4)
return 2;
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
ndr->data[2] != 0 || ndr->data[3] != 0)
return 3;
');
test_samba4_ndr("ptr-top-out-pull",
'
typedef struct {
uint16 x;
} xstruct;
[public] void echo_TestRef([out] xstruct *foo);
',
'
uint8_t data[] = { 0x0D, 0x00 };
DATA_BLOB b = { data, 2 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct xstruct s;
struct echo_TestRef r;
r.out.foo = &s;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
return 1;
if (!r.out.foo)
return 2;
if (r.out.foo->x != 13)
return 3;
');
test_samba4_ndr("ptr-top-out-pull-null",
'
typedef struct {
uint16 x;
} xstruct;
[public] void echo_TestRef([out] xstruct *foo);
',
'
uint8_t data[] = { 0x0D, 0x00 };
DATA_BLOB b = { data, 2 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct echo_TestRef r;
r.out.foo = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
return 1;
/* Windows gives [client runtime error 0x6f4] */
');
test_samba4_ndr("refptr-top-out-pull",
'
typedef struct {
uint16 x;
} xstruct;
[public] void echo_TestRef([out,ref] xstruct *foo);
',
'
uint8_t data[] = { 0x0D, 0x00 };
DATA_BLOB b = { data, 2 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct xstruct s;
struct echo_TestRef r;
r.out.foo = &s;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
return 1;
if (!r.out.foo)
return 2;
if (r.out.foo->x != 13)
return 3;
');
test_samba4_ndr("refptr-top-out-pull-null",
'
typedef struct {
uint16 x;
} xstruct;
[public] void echo_TestRef([out,ref] xstruct *foo);
',
'
uint8_t data[] = { 0x0D, 0x00 };
DATA_BLOB b = { data, 2 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL, NULL);
struct echo_TestRef r;
r.out.foo = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_echo_TestRef(ndr, NDR_OUT, &r)))
return 1;
/* Windows gives [client runtime error 0x6f4] */
');
test_samba4_ndr("ptr-top-push-double",
'
[public] void echo_TestRef([in] uint16 **foo);
',
' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
uint16_t v = 13;
uint16_t *pv = &v;
r.in.foo = &pv;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 6)
return 2;
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
ndr->data[2] == 0 && ndr->data[3] == 0)
return 3;
if (ndr->data[4] != 0x0D || ndr->data[5] != 0x00)
return 4;
');
SKIP: {
skip "ptr-top-push-double-sndnull is known to fail", 8;
test_samba4_ndr("ptr-top-push-double-sndnull",
'
[public] void echo_TestRef([in] uint16 **foo);
',
' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
uint16_t *pv = NULL;
r.in.foo = &pv;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 4)
return 2;
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
ndr->data[2] != 0 || ndr->data[3] != 0)
return 3;
');
}
test_samba4_ndr("ptr-top-push-double-fstnull",
'
[public] void echo_TestRef([in] uint16 **foo);
',
' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
/* Windows gives [client runtime error 0x6f4] */
');
test_samba4_ndr("refptr-top-push-double",
'
[public] void echo_TestRef([in,ref] uint16 **foo);
',
' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
uint16_t v = 13;
uint16_t *pv = &v;
r.in.foo = &pv;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 6)
return 2;
if (ndr->data[0] == 0 && ndr->data[1] == 0 &&
ndr->data[2] == 0 && ndr->data[3] == 0)
return 3;
if (ndr->data[4] != 0x0D || ndr->data[5] != 0x00)
return 4;
');
SKIP: {
skip "refptr-top-push-double-sndnull is known to fail", 8;
test_samba4_ndr("refptr-top-push-double-sndnull",
'
[public] void echo_TestRef([in,ref] uint16 **foo);
',
' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
uint16_t *pv = NULL;
r.in.foo = &pv;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 4)
return 2;
if (ndr->data[0] != 0 || ndr->data[1] != 0 ||
ndr->data[2] != 0 || ndr->data[3] != 0)
return 3;
');
}
test_samba4_ndr("refptr-top-push-double-fstnull",
'
[public] void echo_TestRef([in,ref] uint16 **foo);
',
' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
r.in.foo = NULL;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
/* Windows gives [client runtime error 0x6f4] */
');
SKIP: {
skip "ignore-ptrs are not supported yet", 8;
test_samba4_ndr("ignore-ptr",
'
[public] void echo_TestRef([in,ignore] uint16 *foo, [in] uint16 *bar);
',
' struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct echo_TestRef r;
uint16_t v = 10;
r.in.foo = &v;
r.in.bar = &v;
if (NDR_ERR_CODE_IS_SUCCESS(ndr_push_echo_TestRef(ndr, NDR_IN, &r)))
return 1;
if (ndr->offset != 4)
return 2;
');
}

View File

@ -0,0 +1,71 @@
#!/usr/bin/perl
# NDR represent_as() / transmit_as() tests
# (C) 2006 Jelmer Vernooij. Published under the GNU GPL
use strict;
use Test::More tests => 2 * 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
test_samba4_ndr('represent_as-simple',
'
void bla([in,represent_as(uint32)] uint8 x);
',
'
uint8_t expected[] = { 0x0D };
DATA_BLOB in_blob = { expected, 1 };
struct ndr_pull *ndr = ndr_pull_init_blob(&in_blob, NULL, NULL);
struct bla r;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
if (r.in.x != 13)
return 2;
',
'
enum ndr_err_code ndr_uint8_to_uint32(uint8_t from, uint32_t *to)
{
*to = from;
return NDR_ERR_SUCCESS;
}
enum ndr_err_code ndr_uint32_to_uint8(uint32_t from, uint8_t *to)
{
*to = from;
return NDR_ERR_SUCCESS;
}
'
);
test_samba4_ndr('transmit_as-simple',
'
void bla([in,transmit_as(uint32)] uint8 x);
',
'
uint8_t expected[] = { 0x0D };
DATA_BLOB in_blob = { expected, 1 };
struct ndr_pull *ndr = ndr_pull_init_blob(&in_blob, NULL, NULL);
struct bla r;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
if (r.in.x != 13)
return 2;
',
'
enum ndr_err_code ndr_uint8_to_uint32(uint8_t from, uint32_t *to)
{
*to = from;
return NDR_ERR_SUCCESS;
}
enum ndr_err_code ndr_uint32_to_uint8(uint32_t from, uint8_t *to)
{
*to = from;
return NDR_ERR_SUCCESS;
}
'
);

28
tools/pidl/tests/ndr_simple.pl Executable file
View File

@ -0,0 +1,28 @@
#!/usr/bin/perl
# Some simple tests for pidl
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use Test::More tests => 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
test_samba4_ndr("simple", "void Test(); ",
"
uint8_t data[] = { 0x02 };
uint8_t result;
DATA_BLOB b;
struct ndr_pull *ndr;
b.data = data;
b.length = 1;
ndr = ndr_pull_init_blob(&b, mem_ctx, NULL);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_uint8(ndr, NDR_SCALARS, &result)))
return 1;
if (result != 0x02)
return 2;
");

192
tools/pidl/tests/ndr_string.pl Executable file
View File

@ -0,0 +1,192 @@
#!/usr/bin/perl
# String tests for pidl
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use Test::More tests => 6 * 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
test_samba4_ndr("string-pull-empty",
' [public] void TestString([in,flag(STR_ASCII|LIBNDR_FLAG_STR_SIZE4)] string data);',
'
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00 };
DATA_BLOB b = { data, 4 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
struct TestString r;
r.in.data = NULL;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r)))
return 1;
if (r.in.data == NULL)
return 2;
if (r.in.data[0] != 0)
return 3;
');
test_samba4_ndr("string-ascii-pull",
'
[public] void TestString([in,flag(STR_ASCII|LIBNDR_FLAG_STR_SIZE4)] string data);
',
'
uint8_t data[] = { 0x03, 0x00, 0x00, 0x00,
\'f\', \'o\', \'o\', 0 };
DATA_BLOB b = { data, 8 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
struct TestString r;
r.in.data = NULL;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r)))
return 1;
if (r.in.data == NULL)
return 2;
if (strncmp(r.in.data, "foo", 3) != 0)
return 3;
if (r.in.data[4] != 0)
return 4;
');
test_samba4_ndr("string-wchar-fixed-array-01",
'
typedef struct {
uint32 l1;
[string,charset(UTF16)] uint16 str[6];
uint32 l2;
} TestStringStruct;
[public] void TestString([in,ref] TestStringStruct *str);
',
'
uint8_t data[] = { 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00,
\'f\', 0x00, \'o\', 0x00,
\'o\', 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00
};
DATA_BLOB b = { data, sizeof(data) };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
struct TestString r;
struct TestStringStruct str;
r.in.str = &str;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r)))
return 1;
if (r.in.str == NULL)
return 2;
if (r.in.str->l1 != 0x00000001)
return 3;
if (strncmp(str.str, "foo", 3) != 0)
return 4;
if (r.in.str->str[4] != 0)
return 5;
if (r.in.str->l2 != 0x00000002)
return 6;
');
test_samba4_ndr("string-wchar-fixed-array-02",
'
typedef struct {
uint32 l1;
[string,charset(UTF16)] uint16 str[6];
uint32 l2;
} TestStringStruct;
[public] void TestString([in,ref] TestStringStruct *str);
',
'
uint8_t data[] = { 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00,
\'f\', 0x00, \'o\', 0x00,
\'o\', 0x00, \'b\', 0x00,
\'a\', 0x00, \'r\', 0x00,
0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00
};
DATA_BLOB b = { data, sizeof(data) };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
struct TestString r;
struct TestStringStruct str;
r.in.str = &str;
/* the string terminator is wrong */
if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r)))
return 1;
');
test_samba4_ndr("string-wchar-fixed-array-03",
'
typedef struct {
uint32 l1;
[string,charset(UTF16)] uint16 str[6];
uint32 l2;
} TestStringStruct;
[public] void TestString([in,ref] TestStringStruct *str);
',
'
uint8_t data[] = { 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00,
\'f\', 0x00, \'o\', 0x00,
\'o\', 0x00, \'b\', 0x00,
\'a\', 0x00, \'r\', 0x00,
0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00
};
DATA_BLOB b = { data, sizeof(data) };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
struct TestString r;
struct TestStringStruct str;
r.in.str = &str;
/* the length 0x07 is to large */
if (NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r)))
return 1;
');
SKIP: {
skip "doesn't seem to work yet", 8;
test_samba4_ndr("string-out",
'
[public] void TestString([out,string,charset(UNIX)] uint8 **data);
',
'
uint8_t data[] = { 0x03, 0x00, 0x00, 0x00,
\'f\', \'o\', \'o\', 0 };
DATA_BLOB b = { data, 8 };
struct ndr_pull *ndr = ndr_pull_init_blob(&b, NULL);
struct TestString r;
char *str = NULL;
r.out.data = &str;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_pull_TestString(ndr, NDR_IN, &r)))
return 1;
if (r.out.data == NULL)
return 2;
if (*r.out.data == NULL)
return 3;
if (strncmp(r.out.data, "foo", 3) != 0)
return 4;
if (r.out.data[4] != 0)
return 5;
');
}

66
tools/pidl/tests/ndr_tagtype.pl Executable file
View File

@ -0,0 +1,66 @@
#!/usr/bin/perl
# Support for tagged types
# (C) 2005 Jelmer Vernooij. Published under the GNU GPL
use strict;
use Test::More tests => 3 * 8;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_samba4_ndr);
test_samba4_ndr('struct-notypedef', '[public] struct bla { uint8 x; }; ',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct bla r;
uint8_t expected[] = { 0x0D };
DATA_BLOB expected_blob = { expected, 1 };
DATA_BLOB result_blob;
r.x = 13;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_STRUCT_bla(ndr, NDR_SCALARS|NDR_BUFFERS, &r)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');
test_samba4_ndr('struct-notypedef-used', '[public] struct bla { uint8 x; };
[public] void myfn([in] struct bla r); ',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct myfn fn;
uint8_t expected[] = { 0x0D };
DATA_BLOB expected_blob = { expected, 1 };
DATA_BLOB result_blob;
fn.in.r.x = 13;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_myfn(ndr, NDR_IN, &fn)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');
test_samba4_ndr('struct-notypedef-embedded', 'struct bla { uint8 x; };
[public] struct myst { struct bla r; }; ',
'
struct ndr_push *ndr = ndr_push_init_ctx(NULL, NULL);
struct myst st;
uint8_t expected[] = { 0x0D };
DATA_BLOB expected_blob = { expected, 1 };
DATA_BLOB result_blob;
st.r.x = 13;
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_STRUCT_myst(ndr, NDR_IN, &st)))
return 1;
result_blob = ndr_push_blob(ndr);
if (data_blob_cmp(&result_blob, &expected_blob) != 0)
return 2;
');

243
tools/pidl/tests/parse_idl.pl Executable file
View File

@ -0,0 +1,243 @@
#!/usr/bin/perl
# Some simple tests for pidls parsing routines
# (C) 2005 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU General Public License
use strict;
use Test::More tests => 65 * 2 + 7;
use FindBin qw($RealBin);
use lib "$RealBin";
use Util qw(test_errors);
use Parse::Pidl::IDL;
use Parse::Pidl::NDR;
sub testok($$)
{
my ($name, $data) = @_;
test_errors("", sub {
my $pidl = Parse::Pidl::IDL::parse_string($data, "<$name>");
ok (defined($pidl), $name);
});
}
sub testfail($$$)
{
my ($name, $data, $error) = @_;
test_errors($error, sub {
my $pidl = Parse::Pidl::IDL::parse_string($data, "<$name>");
ok ((not defined $pidl), $name);
});
}
testfail "unknowntag", "bla test {};",
"<unknowntag>:0: Syntax error near 'bla'\n";
testok "test1", "interface test { void Test(); }; ";
testok "voidtest", "interface test { int Testx(void); }; ";
testfail "voidtest", "interface test { Test(); }; ",
"<voidtest>:0: Syntax error near '('\n";
testok "argtest", "interface test { int Test(int a, long b, uint32 c); }; ";
testok "array1", "interface test { int Test(int a[]); };";
testok "array2", "interface test { int Test(int a[2]); };";
testok "array3", "interface test { int Test(int a[b]); };";
testfail "array4", "interface test { int Test(int[] a); };",
"<array4>:0: Syntax error near '['\n";
testok "ptr1", "interface test { int Test(int *a); };";
testok "ptr2", "interface test { int Test(int **a); };";
testok "ptr3", "interface test { int Test(int ***a); };";
testfail "empty1", "interface test { };", "<empty1>:0: Syntax error near '}'\n";
testfail "empty2", "", "";
testok "attr1", "[uuid(\"myuuid\"),attr] interface test { int Test(int ***a); };";
testok "attr2", "interface test { [public] int Test(); };";
testok "attr3", "[attr1] [attr2] interface test { [public] int Test(); };";
testok "multfn", "interface test { int test1(); int test2(); };";
testok "multif", "interface test { int test1(); }; interface test2 { int test2(); };";
testok "tdstruct1", "interface test { typedef struct { } foo; };";
testok "tdstruct2", "interface test { typedef struct { int a; } foo; };";
testok "tdstruct3", "interface test { typedef struct { int a; int b; } foo; };";
testfail "tdstruct4", "interface test { typedef struct { int a, int b; } foo; };",
"<tdstruct4>:0: Syntax error near ','\n";
testok "struct1", "interface test { struct x { }; };";
testok "struct2", "interface test { struct x { int a; }; };";
testok "struct3", "interface test { struct x { int a; int b; }; };";
testfail "struct4", "interface test { struct x { int a, int b; }; };",
"<struct4>:0: Syntax error near ','\n";
testfail "struct5", "interface test { struct { int a; } x; };",
"<struct5>:0: Syntax error near 'x'\n";
testok "tdunion1", "interface test { typedef union { } a; };";
testok "tdunion2", "interface test { typedef union { int a; } a; };";
testok "union1", "interface test { union a { }; };";
testok "union2", "interface test { union x { int a; }; };";
testfail "union3", "interface test { union { int a; } x; };",
"<union3>:0: Syntax error near 'x'\n";
testok "typedef1", "interface test { typedef int a; };";
testfail "typedef2", "interface test { typedef x; };",
"<typedef2>:0: Syntax error near ';'\n";
testok "tdenum1", "interface test { typedef enum { A=1, B=2, C} a; };";
testok "enum1", "interface test { enum a { A=1, B=2, C}; };";
testfail "enum2", "interface test { enum { A=1, B=2, C} a; };",
"<enum2>:0: Syntax error near 'a'\n";
testok "nested1", "interface test { struct x { struct { int a; } z; }; };";
testok "nested2", "interface test { struct x { struct y { int a; } z; }; };";
testok "bitmap1", "interface test { bitmap x { a=1 }; };";
testok "unsigned", "interface test { struct x { unsigned short y; }; };";
testok "struct-property", "interface test { [public] struct x { short y; }; };";
testok "signed", "interface test { struct x { signed short y; }; };";
testok "declarg", "interface test { void test(struct { int x; } a); };";
testok "structarg", "interface test { void test(struct a b); };";
testfail "structargmissing", "interface test { void test(struct a); };",
"<structargmissing>:0: Syntax error near ')'\n";
testok "structqual", "interface test { struct x { struct y z; }; };";
testok "unionqual", "interface test { struct x { union y z; }; };";
testok "enumqual", "interface test { struct x { enum y z; }; };";
testok "bitmapqual", "interface test { struct x { bitmap y z; }; };";
testok "emptystructdecl", "interface test { struct x; };";
testok "emptyenumdecl", "interface test { enum x; };";
testok "emptytdstructdecl", "interface test { typedef struct x y; };";
testok "import", "import \"foo.idl\";";
testok "include", "include \"foo.h\";";
testfail "import-noquotes", "import foo.idl;",
"<import-noquotes>:0: Syntax error near 'foo'\n";
testfail "include-noquotes", "include foo.idl;",
"<include-noquotes>:0: Syntax error near 'foo'\n";
testok "importlib", "importlib \"foo.idl\";";
testfail "import-nosemicolon", "import \"foo.idl\"",
"<import-nosemicolon>:0: Syntax error near 'foo.idl'\n";
testok "import-multiple", "import \"foo.idl\", \"bar.idl\";";
testok "include-multiple", "include \"foo.idl\", \"bar.idl\";";
testok "empty-struct", "interface test { struct foo { }; }";
testok "typedef-double", "interface test { typedef struct foo { } foo; }";
testok "cpp-quote", "cpp_quote(\"bla\")";
my $x = Parse::Pidl::IDL::parse_string("interface foo { struct x {}; }", "<foo>");
is_deeply($x, [ {
'TYPE' => 'INTERFACE',
'NAME' => 'foo',
'DATA' => [ {
'TYPE' => 'STRUCT',
'NAME' => 'x',
'ELEMENTS' => [],
'FILE' => '<foo>',
'LINE' => 0
} ],
'FILE' => '<foo>',
'LINE' => 0
}]);
$x = Parse::Pidl::IDL::parse_string("interface foo { struct x; }", "<foo>");
is_deeply($x, [ {
'TYPE' => 'INTERFACE',
'NAME' => 'foo',
'DATA' => [ {
'TYPE' => 'STRUCT',
'NAME' => 'x',
'FILE' => '<foo>',
'LINE' => 0
} ],
'FILE' => '<foo>',
'LINE' => 0
}]);
$x = Parse::Pidl::IDL::parse_string("cpp_quote(\"foobar\")", "<quote>");
is_deeply($x, [ {
'TYPE' => 'CPP_QUOTE',
'DATA' => '"foobar"',
'FILE' => '<quote>',
'LINE' => 0
}]);
# A typedef of a struct without body
$x = Parse::Pidl::IDL::parse_string("interface foo { typedef struct x y; }", "<foo>");
is_deeply($x, [ {
'TYPE' => 'INTERFACE',
'NAME' => 'foo',
'DATA' => [ {
'TYPE' => 'TYPEDEF',
'NAME' => 'y',
'POINTERS' => 0,
'DATA' => {
'TYPE' => 'STRUCT',
'NAME' => 'x',
'FILE' => '<foo>',
'LINE' => 0,
},
'FILE' => '<foo>',
'LINE' => 0,
} ],
'FILE' => '<foo>',
'LINE' => 0
}]);
# A typedef of a struct with empty body
$x = Parse::Pidl::IDL::parse_string("interface foo { typedef struct {} y; }", "<foo>");
is_deeply($x, [ {
'TYPE' => 'INTERFACE',
'NAME' => 'foo',
'DATA' => [ {
'TYPE' => 'TYPEDEF',
'NAME' => 'y',
'POINTERS' => 0,
'DATA' => {
'TYPE' => 'STRUCT',
'ELEMENTS' => [],
'FILE' => '<foo>',
'LINE' => 0
},
'FILE' => '<foo>',
'LINE' => 0
} ],
'FILE' => '<foo>',
'LINE' => 0
}]);
# A typedef of a bitmap with no body
$x = Parse::Pidl::IDL::parse_string("interface foo { typedef bitmap x y; }", "<foo>");
is_deeply($x, [ {
'TYPE' => 'INTERFACE',
'NAME' => 'foo',
'DATA' => [ {
'TYPE' => 'TYPEDEF',
'NAME' => 'y',
'POINTERS' => 0,
'DATA' => {
'TYPE' => 'BITMAP',
'NAME' => 'x',
'FILE' => '<foo>',
'LINE' => 0
},
'FILE' => '<foo>',
'LINE' => 0
} ],
'FILE' => '<foo>',
'LINE' => 0
}]);
# A typedef of a union with no body
$x = Parse::Pidl::IDL::parse_string("interface foo { typedef union x y; }", "<foo>");
is_deeply($x, [ {
'TYPE' => 'INTERFACE',
'NAME' => 'foo',
'DATA' => [ {
'TYPE' => 'TYPEDEF',
'NAME' => 'y',
'POINTERS' => 0,
'DATA' => {
'TYPE' => 'UNION',
'NAME' => 'x',
'FILE' => '<foo>',
'LINE' => 0
},
'FILE' => '<foo>',
'LINE' => 0
} ],
'FILE' => '<foo>',
'LINE' => 0
}]);

Some files were not shown because too many files have changed in this diff Show More