2004-12-14 02:02:18 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* User Runtime Loader support in the kernel */
|
2003-01-12 18:58:08 +03:00
|
|
|
|
|
|
|
|
|
|
|
#include <KernelExport.h>
|
2004-12-14 02:02:18 +03:00
|
|
|
#include <kernel.h>
|
2003-01-12 18:58:08 +03:00
|
|
|
#include <kimage.h>
|
2004-12-14 02:02:18 +03:00
|
|
|
#include <lock.h>
|
2003-01-12 18:58:08 +03:00
|
|
|
#include <thread.h>
|
2004-03-16 05:53:41 +03:00
|
|
|
#include <team.h>
|
2003-01-12 18:58:08 +03:00
|
|
|
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
//#define TRACE_IMAGE
|
|
|
|
#ifdef TRACE_IMAGE
|
|
|
|
# define TRACE(x) dprintf x
|
|
|
|
#else
|
|
|
|
# define TRACE(x) ;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2003-01-12 18:58:08 +03:00
|
|
|
struct image {
|
|
|
|
struct image *next;
|
|
|
|
struct image *prev;
|
|
|
|
image_info info;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
static image_id sNextImageID = 1;
|
|
|
|
static mutex sImageMutex;
|
2003-01-12 18:58:08 +03:00
|
|
|
|
|
|
|
|
|
|
|
/** Registers an image with the specified team.
|
|
|
|
*/
|
|
|
|
|
|
|
|
image_id
|
2004-05-11 19:04:36 +04:00
|
|
|
register_image(struct team *team, image_info *_info, size_t size)
|
2003-01-12 18:58:08 +03:00
|
|
|
{
|
2004-05-11 19:04:36 +04:00
|
|
|
image_id id = atomic_add(&sNextImageID, 1);
|
2003-01-12 18:58:08 +03:00
|
|
|
struct image *image;
|
|
|
|
|
2004-10-18 19:39:21 +04:00
|
|
|
image = malloc(sizeof(struct image));
|
2003-01-12 18:58:08 +03:00
|
|
|
if (image == NULL)
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
|
|
|
|
memcpy(&image->info, _info, sizeof(image_info));
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_lock(&sImageMutex);
|
2003-01-12 18:58:08 +03:00
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
image->info.id = id;
|
|
|
|
list_add_item(&team->image_list, image);
|
2003-01-12 18:58:08 +03:00
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_unlock(&sImageMutex);
|
2003-01-12 18:58:08 +03:00
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
TRACE(("register_image(team = %p, image id = %ld, image = %p\n", team, id, image));
|
2003-01-12 18:58:08 +03:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Unregisters an image from the specified team.
|
|
|
|
*/
|
|
|
|
|
|
|
|
status_t
|
2004-05-11 19:04:36 +04:00
|
|
|
unregister_image(struct team *team, image_id id)
|
2003-01-12 18:58:08 +03:00
|
|
|
{
|
|
|
|
status_t status = B_ENTRY_NOT_FOUND;
|
2004-05-11 19:04:36 +04:00
|
|
|
struct image *image = NULL;
|
2003-01-12 18:58:08 +03:00
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_lock(&sImageMutex);
|
2003-01-27 02:31:38 +03:00
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
|
|
|
|
if (image->info.id == id) {
|
|
|
|
list_remove_link(image);
|
|
|
|
free(image);
|
|
|
|
status = B_OK;
|
|
|
|
break;
|
2003-01-12 18:58:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_unlock(&sImageMutex);
|
2003-01-12 18:58:08 +03:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Counts the registered images from the specified team.
|
|
|
|
* The team lock must be hold when you call this function.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int32
|
|
|
|
count_images(struct team *team)
|
|
|
|
{
|
2003-01-27 02:31:38 +03:00
|
|
|
struct image *image = NULL;
|
2003-01-12 18:58:08 +03:00
|
|
|
int32 count = 0;
|
2003-01-27 02:31:38 +03:00
|
|
|
|
|
|
|
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
|
2003-01-12 18:58:08 +03:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Removes all images from the specified team. Must only be called
|
|
|
|
* with the team lock hold or a team that has already been removed
|
|
|
|
* from the list (in thread_exit()).
|
|
|
|
*/
|
|
|
|
|
|
|
|
status_t
|
|
|
|
remove_images(struct team *team)
|
|
|
|
{
|
2003-01-27 02:31:38 +03:00
|
|
|
struct image *image;
|
2003-01-12 18:58:08 +03:00
|
|
|
|
|
|
|
ASSERT(team != NULL);
|
|
|
|
|
2003-01-27 02:31:38 +03:00
|
|
|
while ((image = list_remove_head_item(&team->image_list)) != NULL) {
|
2003-01-12 18:58:08 +03:00
|
|
|
free(image);
|
|
|
|
}
|
2003-01-13 19:37:47 +03:00
|
|
|
return B_OK;
|
2003-01-12 18:58:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
_get_image_info(image_id id, image_info *info, size_t size)
|
|
|
|
{
|
|
|
|
status_t status = B_ENTRY_NOT_FOUND;
|
2004-05-11 19:04:36 +04:00
|
|
|
struct team *team = thread_get_current_thread()->team;
|
|
|
|
struct image *image = NULL;
|
2003-01-12 18:58:08 +03:00
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_lock(&sImageMutex);
|
2003-01-27 02:31:38 +03:00
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
|
|
|
|
if (image->info.id == id) {
|
|
|
|
memcpy(info, &image->info, size);
|
|
|
|
status = B_OK;
|
|
|
|
break;
|
2003-01-12 18:58:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_unlock(&sImageMutex);
|
2003-01-12 18:58:08 +03:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
_get_next_image_info(team_id teamID, int32 *cookie, image_info *info, size_t size)
|
|
|
|
{
|
|
|
|
status_t status = B_ENTRY_NOT_FOUND;
|
|
|
|
struct team *team;
|
|
|
|
cpu_status state;
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_lock(&sImageMutex);
|
|
|
|
|
2003-01-12 18:58:08 +03:00
|
|
|
state = disable_interrupts();
|
|
|
|
GRAB_TEAM_LOCK();
|
|
|
|
|
2005-01-14 18:32:14 +03:00
|
|
|
if (teamID == 0)
|
|
|
|
team = thread_get_current_thread()->team;
|
|
|
|
else
|
|
|
|
team = team_get_team_struct_locked(teamID);
|
2003-01-12 18:58:08 +03:00
|
|
|
if (team) {
|
2003-01-27 02:31:38 +03:00
|
|
|
struct image *image = NULL;
|
2003-01-12 18:58:08 +03:00
|
|
|
int32 count = 0;
|
2003-01-27 02:31:38 +03:00
|
|
|
|
|
|
|
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
|
2003-01-12 18:58:08 +03:00
|
|
|
if (count == *cookie) {
|
|
|
|
memcpy(info, &image->info, size);
|
|
|
|
status = B_OK;
|
|
|
|
(*cookie)++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
status = B_BAD_TEAM_ID;
|
|
|
|
|
|
|
|
RELEASE_TEAM_LOCK();
|
|
|
|
restore_interrupts(state);
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
mutex_unlock(&sImageMutex);
|
|
|
|
|
2003-01-12 18:58:08 +03:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-08-13 20:31:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
static int
|
|
|
|
dump_images_list(int argc, char **argv)
|
|
|
|
{
|
|
|
|
struct team *team = thread_get_current_thread()->team;
|
|
|
|
struct image *image = NULL;
|
|
|
|
|
|
|
|
dprintf("Registered images of team 0x%lx\n", team->id);
|
|
|
|
dprintf(" ID text size data size name\n");
|
|
|
|
|
|
|
|
mutex_lock(&sImageMutex);
|
|
|
|
|
|
|
|
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
|
|
|
|
image_info *info = &image->info;
|
|
|
|
|
|
|
|
dprintf("%6ld %p %-7ld %p %-7ld %s\n", info->id, info->text, info->text_size,
|
|
|
|
info->data, info->data_size, info->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
mutex_unlock(&sImageMutex);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
status_t
|
|
|
|
image_init(void)
|
|
|
|
{
|
2004-08-13 20:31:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
add_debugger_command("team_images", &dump_images_list, "Dump all registered images from the current team");
|
|
|
|
#endif
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
return mutex_init(&sImageMutex, "image");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-01-12 18:58:08 +03:00
|
|
|
// #pragma mark -
|
|
|
|
// Functions exported for the user space
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2004-05-11 19:04:36 +04:00
|
|
|
_user_unregister_image(image_id id)
|
2003-01-12 18:58:08 +03:00
|
|
|
{
|
2004-05-11 19:04:36 +04:00
|
|
|
return unregister_image(thread_get_current_thread()->team, id);
|
2003-01-12 18:58:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
image_id
|
2004-05-11 19:04:36 +04:00
|
|
|
_user_register_image(image_info *userInfo, size_t size)
|
2003-01-12 18:58:08 +03:00
|
|
|
{
|
|
|
|
image_info info;
|
|
|
|
|
|
|
|
if (size != sizeof(image_info))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userInfo)
|
2003-01-12 18:58:08 +03:00
|
|
|
|| user_memcpy(&info, userInfo, size) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
2004-05-11 19:04:36 +04:00
|
|
|
return register_image(thread_get_current_thread()->team, &info, size);
|
2003-01-12 18:58:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2004-05-11 19:04:36 +04:00
|
|
|
_user_get_image_info(image_id id, image_info *userInfo, size_t size)
|
2003-01-12 18:58:08 +03:00
|
|
|
{
|
|
|
|
image_info info;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
if (size != sizeof(image_info))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userInfo))
|
2003-01-12 18:58:08 +03:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
status = _get_image_info(id, &info, size);
|
|
|
|
|
|
|
|
if (user_memcpy(userInfo, &info, size) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
2004-05-11 19:04:36 +04:00
|
|
|
_user_get_next_image_info(team_id team, int32 *_cookie, image_info *userInfo, size_t size)
|
2003-01-12 18:58:08 +03:00
|
|
|
{
|
|
|
|
image_info info;
|
|
|
|
status_t status;
|
|
|
|
|
|
|
|
if (size != sizeof(image_info))
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
2004-02-22 17:52:59 +03:00
|
|
|
if (!IS_USER_ADDRESS(userInfo) || !IS_USER_ADDRESS(_cookie))
|
2003-01-12 18:58:08 +03:00
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
status = _get_next_image_info(team, _cookie, &info, size);
|
|
|
|
|
|
|
|
if (user_memcpy(userInfo, &info, size) < B_OK)
|
|
|
|
return B_BAD_ADDRESS;
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|