Add ability to generate newc additions on runtime.

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2013-03-22 21:01:28 +01:00
parent 0ec45a682c
commit 92750e4c60
10 changed files with 366 additions and 201 deletions

View File

@ -1,3 +1,7 @@
2013-03-22 Vladimir Serbinenko <phcoder@gmail.com>
Add ability to generate newc additions on runtime.
2013-03-22 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/commands/i386/coreboot/cbls.c: Fix typos and wrong

View File

@ -1406,6 +1406,7 @@ module = {
module = {
name = linux16;
common = loader/i386/pc/linux.c;
common = loader/linux.c;
common = lib/cmdline.c;
enable = x86;
};
@ -1454,6 +1455,7 @@ module = {
powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
ia64_efi = loader/ia64/efi/linux.c;
common = loader/linux.c;
common = lib/cmdline.c;
enable = noemu;
};

View File

@ -34,6 +34,7 @@
#include <grub/i386/relocator.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -1055,14 +1056,11 @@ static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t *files = 0;
grub_size_t size = 0;
grub_addr_t addr_min, addr_max;
grub_addr_t addr;
grub_err_t err;
int i;
int nfiles = 0;
grub_uint8_t *ptr;
struct grub_linux_initrd_context initrd_ctx;
if (argc == 0)
{
@ -1076,19 +1074,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
files = grub_zalloc (argc * sizeof (files[0]));
if (!files)
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
for (i = 0; i < argc; i++)
{
grub_file_filter_disable_compression ();
files[i] = grub_file_open (argv[i]);
if (! files[i])
goto fail;
nfiles++;
size += ALIGN_UP (grub_file_size (files[i]), 4);
}
size = grub_get_initrd_size (&initrd_ctx);
initrd_pages = (page_align (size) >> 12);
@ -1138,21 +1127,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
initrd_mem_target = get_physical_target_address (ch);
}
ptr = initrd_mem;
for (i = 0; i < nfiles; i++)
{
grub_ssize_t cursize = grub_file_size (files[i]);
if (grub_file_read (files[i], ptr, cursize) != cursize)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
goto fail;
}
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
goto fail;
grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
(unsigned) addr, (unsigned) size);
@ -1162,9 +1138,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
linux_params.root_dev = 0x0100; /* XXX */
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
grub_free (files);
grub_initrd_close (&initrd_ctx);
return grub_errno;
}

View File

@ -34,6 +34,7 @@
#include <grub/video.h>
#include <grub/i386/floppy.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -381,15 +382,13 @@ static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t *files = 0;
grub_size_t size = 0;
grub_addr_t addr_max, addr_min;
struct linux_kernel_header *lh;
grub_uint8_t *initrd_chunk;
grub_addr_t initrd_addr;
grub_err_t err;
int i, nfiles = 0;
grub_uint8_t *ptr;
struct grub_linux_initrd_context initrd_ctx;
if (argc == 0)
{
@ -437,19 +436,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
addr_min = GRUB_LINUX_BZIMAGE_ADDR + grub_linux16_prot_size;
files = grub_zalloc (argc * sizeof (files[0]));
if (!files)
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
for (i = 0; i < argc; i++)
{
grub_file_filter_disable_compression ();
files[i] = grub_file_open (argv[i]);
if (! files[i])
goto fail;
nfiles++;
size += ALIGN_UP (grub_file_size (files[i]), 4);
}
size = grub_get_initrd_size (&initrd_ctx);
{
grub_relocator_chunk_t ch;
@ -463,30 +453,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
initrd_addr = get_physical_target_address (ch);
}
ptr = initrd_chunk;
for (i = 0; i < nfiles; i++)
{
grub_ssize_t cursize = grub_file_size (files[i]);
if (grub_file_read (files[i], ptr, cursize) != cursize)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
goto fail;
}
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
if (grub_initrd_load (&initrd_ctx, argv, initrd_chunk))
goto fail;
lh->ramdisk_image = initrd_addr;
lh->ramdisk_size = size;
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
grub_free (files);
grub_initrd_close (&initrd_ctx);
return grub_errno;
}

View File

@ -32,6 +32,7 @@
#include <grub/elf.h>
#include <grub/i18n.h>
#include <grub/env.h>
#include <grub/linux.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -567,10 +568,7 @@ static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t *files = 0;
int i;
int nfiles = 0;
grub_uint8_t *ptr;
struct grub_linux_initrd_context initrd_ctx;
if (argc == 0)
{
@ -584,22 +582,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
files = grub_zalloc (argc * sizeof (files[0]));
if (!files)
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
initrd_size = 0;
initrd_size = grub_get_initrd_size (&initrd_ctx);
grub_dprintf ("linux", "Loading initrd\n");
for (i = 0; i < argc; i++)
{
grub_file_filter_disable_compression ();
files[i] = grub_file_open (argv[i]);
if (! files[i])
goto fail;
nfiles++;
initrd_size += ALIGN_UP (grub_file_size (files[i]), 4);
grub_dprintf ("linux", "File %d: %s\n", i, argv[i]);
}
initrd_pages = (page_align (initrd_size) >> 12);
initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
@ -612,25 +599,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("linux", "[addr=0x%lx, size=0x%lx]\n",
(grub_uint64_t) initrd_mem, initrd_size);
ptr = initrd_mem;
for (i = 0; i < nfiles; i++)
{
grub_ssize_t cursize = grub_file_size (files[i]);
if (grub_file_read (files[i], ptr, cursize) != cursize)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
goto fail;
}
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
goto fail;
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
grub_free (files);
grub_initrd_close (&initrd_ctx);
return grub_errno;
}

294
grub-core/loader/linux.c Normal file
View File

@ -0,0 +1,294 @@
#include <grub/types.h>
#include <grub/err.h>
#include <grub/linux.h>
#include <grub/misc.h>
#include <grub/file.h>
#include <grub/mm.h>
struct newc_head
{
char magic[6];
char ino[8];
char mode[8];
char uid[8];
char gid[8];
char nlink[8];
char mtime[8];
char filesize[8];
char devmajor[8];
char devminor[8];
char rdevmajor[8];
char rdevminor[8];
char namesize[8];
char check[8];
} __attribute__ ((packed));
struct grub_linux_initrd_component
{
grub_file_t file;
char *newc_name;
grub_off_t size;
};
struct dir
{
char *name;
struct dir *next;
struct dir *child;
};
static char
hex (grub_uint8_t val)
{
if (val < 10)
return '0' + val;
return 'a' + val - 10;
}
static void
set_field (char *var, grub_uint32_t val)
{
int i;
char *ptr = var;
for (i = 28; i >= 0; i -= 4)
*ptr++ = hex((val >> i) & 0xf);
}
static grub_uint8_t *
make_header (grub_uint8_t *ptr,
const char *name, grub_size_t len,
grub_uint32_t mode,
grub_off_t fsize)
{
struct newc_head *head = (struct newc_head *) ptr;
grub_uint8_t *optr;
grub_size_t oh = 0;
grub_memcpy (head->magic, "070701", 6);
set_field (head->ino, 0);
set_field (head->mode, mode);
set_field (head->uid, 0);
set_field (head->gid, 0);
set_field (head->nlink, 1);
set_field (head->mtime, 0);
set_field (head->filesize, fsize);
set_field (head->devmajor, 0);
set_field (head->devminor, 0);
set_field (head->rdevmajor, 0);
set_field (head->rdevminor, 0);
set_field (head->namesize, len);
set_field (head->check, 0);
optr = ptr;
ptr += sizeof (struct newc_head);
grub_memcpy (ptr, name, len);
ptr += len;
oh = ALIGN_UP_OVERHEAD (ptr - optr, 4);
grub_memset (ptr, 0, oh);
ptr += oh;
return ptr;
}
static void
free_dir (struct dir *root)
{
if (!root)
return;
free_dir (root->next);
free_dir (root->child);
grub_free (root->name);
grub_free (root);
}
static grub_size_t
insert_dir (const char *name, struct dir **root,
grub_uint8_t *ptr)
{
struct dir *cur, **head = root;
const char *cb, *ce = name;
grub_size_t size = 0;
while (1)
{
for (cb = ce; *cb == '/'; cb++);
for (ce = cb; *ce && *ce != '/'; ce++);
if (!*ce)
break;
for (cur = *root; cur; cur = cur->next)
if (grub_memcmp (cur->name, cb, ce - cb)
&& cur->name[ce - cb] == 0)
break;
if (!cur)
{
struct dir *n;
n = grub_zalloc (sizeof (*n));
if (!n)
return 0;
n->next = *head;
n->name = grub_strndup (cb, ce - cb);
if (ptr)
{
grub_printf ("Creating directory %s, %s\n", name, ce);
ptr = make_header (ptr, name, ce - name,
040777, 0);
}
size += ALIGN_UP ((ce - (char *) name)
+ sizeof (struct newc_head), 4);
*head = n;
cur = n;
}
root = &cur->next;
}
return size;
}
grub_err_t
grub_initrd_init (int argc, char *argv[],
struct grub_linux_initrd_context *initrd_ctx)
{
int i;
int newc = 0;
struct dir *root = 0;
initrd_ctx->nfiles = 0;
initrd_ctx->components = 0;
initrd_ctx->components = grub_zalloc (argc
* sizeof (initrd_ctx->components[0]));
if (!initrd_ctx->components)
return grub_errno;
initrd_ctx->size = 0;
for (i = 0; i < argc; i++)
{
const char *fname = argv[i];
if (grub_memcmp (argv[i], "newc:", 5) == 0)
{
const char *ptr, *eptr;
ptr = argv[i] + 5;
while (*ptr == '/')
ptr++;
eptr = grub_strchr (ptr, ':');
if (eptr)
{
grub_file_filter_disable_compression ();
initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
if (!initrd_ctx->components[i].newc_name)
{
grub_initrd_close (initrd_ctx);
return grub_errno;
}
initrd_ctx->size
+= ALIGN_UP (sizeof (struct newc_head)
+ grub_strlen (initrd_ctx->components[i].newc_name),
4);
initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name,
&root, 0);
newc = 1;
fname = eptr + 1;
}
}
else if (newc)
{
initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
+ sizeof ("TRAILER!!!") - 1, 4);
free_dir (root);
root = 0;
newc = 0;
}
grub_file_filter_disable_compression ();
initrd_ctx->components[i].file = grub_file_open (fname);
if (!initrd_ctx->components[i].file)
{
grub_initrd_close (initrd_ctx);
return grub_errno;
}
initrd_ctx->nfiles++;
initrd_ctx->components[i].size
= grub_file_size (initrd_ctx->components[i].file);
initrd_ctx->size += ALIGN_UP (initrd_ctx->components[i].size, 4);
}
if (newc)
{
initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
+ sizeof ("TRAILER!!!") - 1, 4);
free_dir (root);
root = 0;
}
return GRUB_ERR_NONE;
}
grub_size_t
grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx)
{
return initrd_ctx->size;
}
void
grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx)
{
int i;
if (!initrd_ctx->components)
return;
for (i = 0; i < initrd_ctx->nfiles; i++)
{
grub_free (initrd_ctx->components[i].newc_name);
grub_file_close (initrd_ctx->components[i].file);
}
grub_free (initrd_ctx->components);
initrd_ctx->components = 0;
}
grub_err_t
grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
char *argv[], void *target)
{
grub_uint8_t *ptr = target;
int i;
int newc = 0;
struct dir *root = 0;
for (i = 0; i < initrd_ctx->nfiles; i++)
{
grub_ssize_t cursize;
if (initrd_ctx->components[i].newc_name)
{
ptr += insert_dir (initrd_ctx->components[i].newc_name,
&root, ptr);
ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
grub_strlen (initrd_ctx->components[i].newc_name),
0100777,
initrd_ctx->components[i].size);
newc = 1;
}
else if (newc)
{
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
0, 0);
free_dir (root);
root = 0;
newc = 0;
}
cursize = initrd_ctx->components[i].size;
if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize)
!= cursize)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
grub_initrd_close (initrd_ctx);
return grub_errno;
}
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
if (newc)
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
free_dir (root);
root = 0;
return GRUB_ERR_NONE;
}

View File

@ -28,6 +28,7 @@
#include <grub/memory.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -410,14 +411,11 @@ static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t *files = 0;
grub_size_t size = 0;
void *initrd_src;
grub_addr_t initrd_dest;
grub_err_t err;
int i;
int nfiles = 0;
grub_uint8_t *ptr;
struct grub_linux_initrd_context initrd_ctx;
if (argc == 0)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@ -428,19 +426,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
if (initrd_loaded)
return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued.");
files = grub_zalloc (argc * sizeof (files[0]));
if (!files)
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
for (i = 0; i < argc; i++)
{
grub_file_filter_disable_compression ();
files[i] = grub_file_open (argv[i]);
if (! files[i])
goto fail;
nfiles++;
size += ALIGN_UP (grub_file_size (files[i]), 4);
}
size = grub_get_initrd_size (&initrd_ctx);
{
grub_relocator_chunk_t ch;
@ -458,21 +447,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
initrd_dest = get_physical_target_address (ch) | 0x80000000;
}
ptr = initrd_src;
for (i = 0; i < nfiles; i++)
{
grub_ssize_t cursize = grub_file_size (files[i]);
if (grub_file_read (files[i], ptr, cursize) != cursize)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
goto fail;
}
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
if (grub_initrd_load (&initrd_ctx, argv, initrd_src))
goto fail;
#ifdef GRUB_MACHINE_MIPS_QEMU_MIPS
{
@ -504,9 +480,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
initrd_loaded = 1;
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
grub_free (files);
grub_initrd_close (&initrd_ctx);
return grub_errno;
}

View File

@ -29,6 +29,7 @@
#include <grub/memory.h>
#include <grub/lib/cmdline.h>
#include <grub/cache.h>
#include <grub/linux.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -315,13 +316,10 @@ static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t *files = 0;
grub_size_t size = 0;
grub_addr_t first_addr;
grub_addr_t addr;
int i;
int nfiles = 0;
grub_uint8_t *ptr;
struct grub_linux_initrd_context initrd_ctx;
if (argc == 0)
{
@ -335,19 +333,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
files = grub_zalloc (argc * sizeof (files[0]));
if (!files)
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
for (i = 0; i < argc; i++)
{
grub_file_filter_disable_compression ();
files[i] = grub_file_open (argv[i]);
if (! files[i])
goto fail;
nfiles++;
size += ALIGN_UP (grub_file_size (files[i]), 4);
}
size = grub_get_initrd_size (&initrd_ctx);
first_addr = linux_addr + linux_size;
@ -359,30 +348,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("loader", "Loading initrd at 0x%x, size 0x%x\n", addr, size);
ptr = (void *) addr;
for (i = 0; i < nfiles; i++)
{
grub_ssize_t cursize = grub_file_size (files[i]);
if (grub_file_read (files[i], ptr, cursize) != cursize)
{
grub_ieee1275_release (addr, size);
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
goto fail;
}
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
if (grub_initrd_load (&initrd_ctx, argv, (void *) addr))
goto fail;
initrd_addr = addr;
initrd_size = size;
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
grub_free (files);
grub_initrd_close (&initrd_ctx);
return grub_errno;
}

View File

@ -28,6 +28,7 @@
#include <grub/i18n.h>
#include <grub/memory.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -368,14 +369,11 @@ static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t *files = 0;
grub_size_t size = 0;
grub_addr_t paddr;
grub_addr_t addr;
int ret;
int i;
int nfiles = 0;
grub_uint8_t *ptr;
struct grub_linux_initrd_context initrd_ctx;
if (argc == 0)
{
@ -389,19 +387,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
files = grub_zalloc (argc * sizeof (files[0]));
if (!files)
if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
for (i = 0; i < argc; i++)
{
grub_file_filter_disable_compression ();
files[i] = grub_file_open (argv[i]);
if (! files[i])
goto fail;
nfiles++;
size += ALIGN_UP(grub_file_size (files[i]), 4);
}
size = grub_get_initrd_size (&initrd_ctx);
addr = 0x60000000;
@ -423,30 +412,15 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("loader", "Loading initrd at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
addr, paddr, size);
ptr = (void *) addr;
for (i = 0; i < nfiles; i++)
{
grub_ssize_t cursize = grub_file_size (files[i]);
if (grub_file_read (files[i], ptr, cursize) != cursize)
{
if (!grub_errno)
grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
argv[i]);
goto fail;
}
ptr += cursize;
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
}
if (grub_initrd_load (&initrd_ctx, argv, (void *) addr))
goto fail;
initrd_addr = addr;
initrd_paddr = paddr;
initrd_size = size;
fail:
for (i = 0; i < nfiles; i++)
grub_file_close (files[i]);
grub_free (files);
grub_initrd_close (&initrd_ctx);
return grub_errno;
}

24
include/grub/linux.h Normal file
View File

@ -0,0 +1,24 @@
#include <grub/file.h>
struct grub_linux_initrd_component;
struct grub_linux_initrd_context
{
int nfiles;
struct grub_linux_initrd_component *components;
grub_size_t size;
};
grub_err_t
grub_initrd_init (int argc, char *argv[],
struct grub_linux_initrd_context *ctx);
grub_size_t
grub_get_initrd_size (struct grub_linux_initrd_context *ctx);
void
grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx);
grub_err_t
grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
char *argv[], void *target);