From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1NN7Yk-0003Bg-4U for mharc-grub-devel@gnu.org; Tue, 22 Dec 2009 11:26:06 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NN7Yg-00039g-7s for grub-devel@gnu.org; Tue, 22 Dec 2009 11:26:02 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NN7Ya-00038N-UA for grub-devel@gnu.org; Tue, 22 Dec 2009 11:26:01 -0500 Received: from [199.232.76.173] (port=55270 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NN7Ya-00038K-OF for grub-devel@gnu.org; Tue, 22 Dec 2009 11:25:56 -0500 Received: from fg-out-1718.google.com ([72.14.220.157]:11413) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NN7YT-0002Ad-WB for grub-devel@gnu.org; Tue, 22 Dec 2009 11:25:55 -0500 Received: by fg-out-1718.google.com with SMTP id 19so3621746fgg.12 for ; Tue, 22 Dec 2009 08:25:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :user-agent:mime-version:to:cc:subject:references:in-reply-to :x-enigmail-version:content-type; bh=+9NBcjNuyakEhjMgXgwhhHN/AYEI8vJktuZGls6ndaM=; b=laM95Z1Hi5eRS+7YoNkRLbsKuW8SbyP42wgW30IaTBANOcUQx/1w91KRnOzRBeBy1/ 71M0nNMCONZ18Gx1RdQfenNpyQP4OvcM4Wg/qv9baZ6iIHNwbE4ZoDKgs0p+54YHQH13 2dkyGOaFrHN32qpHU8ikePc1Sy+Im6m12/jZk= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:x-enigmail-version:content-type; b=Gi6LF+XAahRR8cuqVpD3aBlnlJ7j27N1UgyMmEyGvOKMWeNHZUvj30rEJYyCWTvBsn WU8dkO3HcGonXKeidTGLsdCDxHrecTrGlMOptfSjmSSYZc62n+E/yc6d7/XBH+dpapDr Ll7SZ8TWaPfXPPcG8nBezOueOHgLlOo/kDeQo= Received: by 10.87.66.21 with SMTP id t21mr852893fgk.49.1261499143439; Tue, 22 Dec 2009 08:25:43 -0800 (PST) Received: from debian.bg45.phnet (27.65.202.62.cust.bluewin.ch [62.202.65.27]) by mx.google.com with ESMTPS id 3sm23940517fge.20.2009.12.22.08.25.38 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 22 Dec 2009 08:25:40 -0800 (PST) Message-ID: <4B30F2FA.7070508@gmail.com> Date: Tue, 22 Dec 2009 17:25:30 +0100 From: =?UTF-8?B?VmxhZGltaXIgJ8+GLWNvZGVyL3BoY29kZXInIFNlcmJpbmVua28=?= User-Agent: Mozilla-Thunderbird 2.0.0.22 (X11/20091109) MIME-Version: 1.0 To: The development of GRUB 2 References: <4116f8730910220433ga7d2237q8a72589713c13d94@mail.gmail.com> In-Reply-To: <4116f8730910220433ga7d2237q8a72589713c13d94@mail.gmail.com> X-Enigmail-Version: 0.95.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="------------enigDA33ADD747C8417359949564" X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: nando4eva@gmail.com Subject: [PATCH] Re: Feature Request: 32-bit mem write and 'setpci -s' type command in menu.lst X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Dec 2009 16:26:02 -0000 This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enigDA33ADD747C8417359949564 Content-Type: multipart/mixed; boundary="------------090504010404060105020807" This is a multi-part message in MIME format. --------------090504010404060105020807 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Nando wrote: > Hi everyone, > > > 2/ Ability to do a setpci -s type command > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > > Also, if possible, could a small subset of 'setpci' be incorporated as > well? I guess I could figure out the address I need to write to by > calculation, but would be nice if I could do the equivalent of the > following in grub, associated with a menu entry. This would help the > DIY ViDock project that needs to setup PCI Bridge windows prior to > Windows load, something that many bios doesn't do, neither does Windows= =2E > > setpci -s 00:02.0 40l=3D20 > I attach two patches. One iorw.diff for reading/writing I/O space. Another one setpci.diff is self-explanatory. But it depends on pciclean patch I posted today. --=20 Regards Vladimir '=CF=86-coder/phcoder' Serbinenko --------------090504010404060105020807 Content-Type: text/x-diff; name="setpci.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline; filename="setpci.diff" =3D=3D=3D added file 'commands/setpci.c' --- commands/setpci.c 1970-01-01 00:00:00 +0000 +++ commands/setpci.c 2009-12-22 15:42:45 +0000 @@ -0,0 +1,340 @@ +/* lspci.c - List PCI devices. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008, 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct pci_register +{ + const char *name; + grub_uint16_t addr; + unsigned size; +}; + +struct pci_register pci_registers[] =3D + { + {"VENDOR_ID", GRUB_PCI_REG_VENDOR , 2}, + {"DEVICE_ID", GRUB_PCI_REG_DEVICE , 2}, + {"COMMAND", GRUB_PCI_REG_COMMAND , 2}, + {"STATUS", GRUB_PCI_REG_STATUS , 2}, + {"REVISION", GRUB_PCI_REG_REVISION , 1}, + {"CLASS_PROG", GRUB_PCI_REG_CLASS + 1 , 1}, + {"CLASS_DEVICE", GRUB_PCI_REG_CLASS + 2 , 2}, + {"CACHE_LINE_SIZE", GRUB_PCI_REG_CACHELINE , 1}, + {"LATENCY_TIMER", GRUB_PCI_REG_LAT_TIMER , 1}, + {"HEADER_TYPE", GRUB_PCI_REG_HEADER_TYPE , 1}, + {"BIST", GRUB_PCI_REG_BIST , 1}, + {"BASE_ADDRESS_0", GRUB_PCI_REG_ADDRESS_REG0, 4}, + {"BASE_ADDRESS_1", GRUB_PCI_REG_ADDRESS_REG1, 4}, + {"BASE_ADDRESS_2", GRUB_PCI_REG_ADDRESS_REG2, 4}, + {"BASE_ADDRESS_3", GRUB_PCI_REG_ADDRESS_REG3, 4}, + {"BASE_ADDRESS_4", GRUB_PCI_REG_ADDRESS_REG4, 4}, + {"BASE_ADDRESS_5", GRUB_PCI_REG_ADDRESS_REG5, 4}, + {"CARDBUS_CIS", GRUB_PCI_REG_CIS_POINTER , 4}, + {"SUBVENDOR_ID", GRUB_PCI_REG_SUBVENDOR , 2}, + {"SUBSYSTEM_ID", GRUB_PCI_REG_SUBSYSTEM , 2}, + {"ROM_ADDRESS", GRUB_PCI_REG_ROM_ADDRESS , 4}, + {"CAP_POINTER", GRUB_PCI_REG_CAP_POINTER , 1}, + {"INTERRUPT_LINE", GRUB_PCI_REG_IRQ_LINE , 1}, + {"INTERRUPT_PIN", GRUB_PCI_REG_IRQ_PIN , 1}, + {"MIN_GNT", GRUB_PCI_REG_MIN_GNT , 1}, + {"MAX_LAT", GRUB_PCI_REG_MIN_GNT , 1}, + }; + +static const struct grub_arg_option options[] =3D + { + {0, 'd', 0, "Select device by vendor and device IDs.", + "[vendor]:[device]", ARG_TYPE_STRING}, + {0, 's', 0, "Select device by its position on the bus.", + "[bus]:[slot][.func]", ARG_TYPE_STRING}, + {0, 'v', 0, "Save read value into variable VARNAME.", + "VARNAME", ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + +static grub_uint32_t pciid_check_mask, pciid_check_value; +static int bus, device, function; +static int check_bus, check_device, check_function; +static grub_uint32_t write_mask, regwrite; +static int regsize; +static grub_uint16_t regaddr; +static const char *varname; + +static int NESTED_FUNC_ATTR +grub_setpci_iter (grub_pci_device_t dev, grub_pci_id_t pciid) +{ + grub_uint32_t regval =3D 0; + grub_pci_address_t addr; + + if ((pciid & pciid_check_mask) !=3D pciid_check_value) + return 0; + + if (check_bus && grub_pci_get_bus (dev) !=3D bus) + return 0; + + if (check_device && grub_pci_get_device (dev) !=3D device) + return 0; + + if (check_function && grub_pci_get_function (dev) !=3D device) + return 0; + + addr =3D grub_pci_make_address (dev, regaddr); + + switch (regsize) + { + case 1: + regval =3D grub_pci_read_byte (addr); + break; + + case 2: + regval =3D grub_pci_read_word (addr); + break; + + case 4: + regval =3D grub_pci_read (addr); + break; + } + + if (varname) + { + char buf[sizeof ("XXXXXXXX")]; + grub_sprintf (buf, "%x", regval); + grub_env_set (varname, buf); + return 1; + } + + if (!write_mask) + { + grub_printf ("Register %x of %d:%d.%d is %x\n", regaddr, + grub_pci_get_bus (dev), + grub_pci_get_device (dev), + grub_pci_get_function (dev), + regval); + return 0; + } + + regval =3D (regval & ~write_mask) | regwrite; + + switch (regsize) + { + case 1: + grub_pci_write_byte (addr, regval); + break; + + case 2: + grub_pci_write_word (addr, regval); + break; + + case 4: + grub_pci_write (addr, regval); + break; + } + + return 0; +} + +static grub_err_t +grub_cmd_setpci (grub_extcmd_t cmd, int argc, char **argv) +{ + const char *ptr; + unsigned i; + + pciid_check_value =3D 0; + pciid_check_mask =3D 0; + + if (cmd->state[0].set) + { + ptr =3D cmd->state[0].arg; + pciid_check_value |=3D (grub_strtoul (ptr, (char **) &ptr, 16) & 0= xffff); + if (grub_errno =3D=3D GRUB_ERR_BAD_NUMBER) + { + grub_errno =3D GRUB_ERR_NONE; + ptr =3D cmd->state[0].arg; + } + else + pciid_check_mask |=3D 0xffff; + if (grub_errno) + return grub_errno; + if (*ptr !=3D ':') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected."); + ptr++; + pciid_check_value |=3D (grub_strtoul (ptr, (char **) &ptr, 16) & 0= xffff) + << 16; + if (grub_errno =3D=3D GRUB_ERR_BAD_NUMBER) + grub_errno =3D GRUB_ERR_NONE; + else + pciid_check_mask |=3D 0xffff0000; + } + + pciid_check_value &=3D pciid_check_mask; + + check_bus =3D check_device =3D check_function =3D 0; + + if (cmd->state[1].set) + { + const char *optr; + =20 + ptr =3D cmd->state[1].arg; + optr =3D ptr; + bus =3D grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno =3D=3D GRUB_ERR_BAD_NUMBER) + { + grub_errno =3D GRUB_ERR_NONE; + ptr =3D optr; + } + else + check_bus =3D 1; + if (grub_errno) + return grub_errno; + if (*ptr !=3D ':') + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Colon expected."); + ptr++; + optr =3D ptr; + device =3D grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno =3D=3D GRUB_ERR_BAD_NUMBER) + { + grub_errno =3D GRUB_ERR_NONE; + ptr =3D optr; + } + else + check_device =3D 1; + if (*ptr =3D=3D '.') + { + ptr++; + function =3D grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + check_function =3D 1; + } + } + + if (cmd->state[2].set) + varname =3D cmd->state[2].arg; + else + varname =3D NULL; + + write_mask =3D 0; + + if (argc =3D=3D 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Command expected."); + + if (argc > 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Only one command is suppo= rted."); + + ptr =3D argv[0]; + + for (i =3D 0; i < ARRAY_SIZE (pci_registers); i++) + { + if (grub_strncmp (ptr, pci_registers[i].name, + grub_strlen (pci_registers[i].name)) =3D=3D 0) + break; + } + if (i =3D=3D ARRAY_SIZE (pci_registers)) + { + regsize =3D 0; + regaddr =3D grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown register"); + } + else + { + regaddr =3D pci_registers[i].addr; + regsize =3D pci_registers[i].size; + ptr +=3D grub_strlen (pci_registers[i].name); + } + + if (grub_errno) + return grub_errno; + + if (*ptr =3D=3D '+') + { + ptr++; + regaddr +=3D grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + } + + if (grub_memcmp (ptr, ".L", sizeof (".L") - 1) =3D=3D 0 + || grub_memcmp (ptr, ".l", sizeof (".l") - 1) =3D=3D 0) + { + regsize =3D 4; + ptr +=3D sizeof (".l") - 1; + } + else if (grub_memcmp (ptr, ".W", sizeof (".W") - 1) =3D=3D 0 + || grub_memcmp (ptr, ".w", sizeof (".w") - 1) =3D=3D 0) + { + regsize =3D 2; + ptr +=3D sizeof (".w") - 1; + } + else if (grub_memcmp (ptr, ".B", sizeof (".B") - 1) =3D=3D 0 + || grub_memcmp (ptr, ".b", sizeof (".b") - 1) =3D=3D 0) + { + regsize =3D 1; + ptr +=3D sizeof (".b") - 1; + } + + if (!regsize) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Unknown register size."); + + write_mask =3D 0; + if (*ptr =3D=3D '=3D') + { + ptr++; + regwrite =3D grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + write_mask =3D 0xffffffff; + if (*ptr =3D=3D ':') + { + ptr++; + write_mask =3D grub_strtoul (ptr, (char **) &ptr, 16); + if (grub_errno) + return grub_errno; + write_mask =3D 0xffffffff; + } + regwrite &=3D write_mask; + } + + if (write_mask && varname) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Option -v isn't valid for writes."); + + grub_pci_iterate (grub_setpci_iter); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(setpci) +{ + cmd =3D grub_register_extcmd ("setpci", grub_cmd_setpci, GRUB_COMMAND_= FLAG_BOTH, + "setpci [-s POSITION] [-d DEVICE] [-v VAR] " + "[REGISTER][=3DVALUE[:MASK]]", + "Manipulate PCI devices.", options); +} + +GRUB_MOD_FINI(setpci) +{ + grub_unregister_extcmd (cmd); +} =3D=3D=3D modified file 'conf/i386.rmk' --- conf/i386.rmk 2009-11-25 22:39:59 +0000 +++ conf/i386.rmk 2009-12-22 15:42:45 +0000 @@ -25,3 +25,9 @@ ata_mod_SOURCES =3D disk/ata.c ata_mod_CFLAGS =3D $(COMMON_CFLAGS) ata_mod_LDFLAGS =3D $(COMMON_LDFLAGS) + +# For setpci.mod +pkglib_MODULES +=3D setpci.mod +setpci_mod_SOURCES =3D commands/setpci.c +setpci_mod_CFLAGS =3D $(COMMON_CFLAGS) +setpci_mod_LDFLAGS =3D $(COMMON_LDFLAGS) --------------090504010404060105020807 Content-Type: text/x-diff; name="iorw.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline; filename="iorw.diff" =3D=3D=3D added file 'commands/iorw.c' --- commands/iorw.c 1970-01-01 00:00:00 +0000 +++ commands/iorw.c 2009-12-22 16:18:48 +0000 @@ -0,0 +1,146 @@ +/* memrw.c - command to read / write physical memory */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +static grub_extcmd_t cmd_read_byte, cmd_read_word, cmd_read_dword; +static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; + +static const struct grub_arg_option options[] =3D + { + {0, 'v', 0, "Save read value into variable VARNAME.", + "VARNAME", ARG_TYPE_STRING}, + {0, 0, 0, 0, 0, 0} + }; + + +static grub_err_t +grub_cmd_read (grub_extcmd_t cmd, int argc, char **argv) +{ + grub_target_addr_t addr; + grub_uint32_t value =3D 0; + char buf[sizeof ("XXXXXXXX")]; + + if (argc !=3D 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of argumen= ts"); + + addr =3D grub_strtoul (argv[0], 0, 0); + switch (cmd->cmd->name[sizeof ("grub_in") - 1]) + { + case 'l': + value =3D grub_inl (addr); + break; + + case 'w': + value =3D grub_inw (addr); + break; + + case 'b': + value =3D grub_inb (addr); + break; + } + + if (cmd->state[0].set) + { + grub_sprintf (buf, "%x", value); + grub_env_set (cmd->state[0].arg, buf); + } + else + grub_printf ("0x%x\n", value); + + return 0; +} + +static grub_err_t +grub_cmd_write (grub_command_t cmd, int argc, char **argv) +{ + grub_target_addr_t addr; + grub_uint32_t value; + grub_uint32_t mask =3D 0xffffffff; + + if (argc !=3D 2 && argc !=3D 3) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of argumen= ts"); + + addr =3D grub_strtoul (argv[0], 0, 0); + value =3D grub_strtoul (argv[1], 0, 0); + if (argc =3D=3D 3) + mask =3D grub_strtoul (argv[2], 0, 0); + value &=3D mask; + switch (cmd->name[sizeof ("grub_out") - 1]) + { + case 'l': + if (mask !=3D 0xffffffff) + grub_outl ((grub_inl (addr) & ~mask) | value, addr); + else + grub_outl (value, addr); + break; + + case 'w': + if ((mask & 0xffff) !=3D 0xffff) + grub_outw ((grub_inw (addr) & ~mask) | value, addr); + else + grub_outw (value, addr); + break; + + case 'b': + if ((mask & 0xff) !=3D 0xff) + grub_outb ((grub_inb (addr) & ~mask) | value, addr); + else + grub_outb (value, addr); + break; + } + + return 0; +} + +GRUB_MOD_INIT(memrw) +{ + cmd_read_byte =3D + grub_register_extcmd ("grub_inb", grub_cmd_read, GRUB_COMMAND_FLAG_B= OTH, + "grub_inb PORT", "Read byte from PORT.", options); + cmd_read_word =3D + grub_register_extcmd ("grub_inw", grub_cmd_read, GRUB_COMMAND_FLAG_B= OTH, + "grub_inw PORT", "Read word from PORT.", options); + cmd_read_dword =3D + grub_register_extcmd ("grub_inl", grub_cmd_read, GRUB_COMMAND_FLAG_B= OTH, + "grub_inl PORT", "Read dword from PORT.", options); + cmd_write_byte =3D + grub_register_command ("grub_outb", grub_cmd_write, + "grub_outb PORT VALUE [MASK]", "Write byte VALUE to PORT."); + cmd_write_word =3D + grub_register_command ("grub_outw", grub_cmd_write, + "grub_outw PORT VALUE [MASK]", "Write word VALUE to PORT."); + cmd_write_dword =3D + grub_register_command ("grub_outl", grub_cmd_write, + "grub_outl ADDR VALUE [MASK]", "Write dword VALUE to PORT."); +} + +GRUB_MOD_FINI(memrw) +{ + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); + grub_unregister_command (cmd_write_byte); + grub_unregister_command (cmd_write_word); + grub_unregister_command (cmd_write_dword); +} =3D=3D=3D modified file 'conf/i386.rmk' --- conf/i386.rmk 2009-11-25 22:39:59 +0000 +++ conf/i386.rmk 2009-12-22 16:18:48 +0000 @@ -25,3 +25,9 @@ ata_mod_SOURCES =3D disk/ata.c ata_mod_CFLAGS =3D $(COMMON_CFLAGS) ata_mod_LDFLAGS =3D $(COMMON_LDFLAGS) + +# For iorw.mod. +pkglib_MODULES +=3D iorw.mod +iorw_mod_SOURCES =3D commands/iorw.c +iorw_mod_CFLAGS =3D $(COMMON_CFLAGS) +iorw_mod_LDFLAGS =3D $(COMMON_LDFLAGS) --------------090504010404060105020807-- --------------enigDA33ADD747C8417359949564 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iF4EAREKAAYFAksw8wIACgkQNak7dOguQgn7mwD9FSGzJm9Er0Nr68Y2jSBC6B31 QW4VXPByuf/cstWAFAUA/2sha5MJka74XCjwTUvGyDLAJxtvokRnxcr++LNYB8mh =iccf -----END PGP SIGNATURE----- --------------enigDA33ADD747C8417359949564--