diff --git a/src/kernel/core/image.c b/src/kernel/core/image.c new file mode 100644 index 0000000000..d3ab1202e8 --- /dev/null +++ b/src/kernel/core/image.c @@ -0,0 +1,265 @@ +/* User Runtime Loader support in the kernel +** +** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +*/ + + +#include +#include +#include +#include + +#include +#include + + +// ToDo: register kernel images as well + +struct image { + struct image *next; + struct image *prev; + image_info info; +}; + + +static image_id gNextImageID = 1; + + +/** Registers an image with the specified team. + */ + +image_id +register_image(team_id teamID, image_info *_info, size_t size) +{ + image_id id = atomic_add(&gNextImageID, 1); + struct image *image; + struct team *team; + cpu_status state; + + image = malloc(sizeof(image_info)); + if (image == NULL) + return B_NO_MEMORY; + + memcpy(&image->info, _info, sizeof(image_info)); + + state = disable_interrupts(); + GRAB_TEAM_LOCK(); + + team = team_get_team_struct_locked(teamID); + if (team) { + image->info.id = id; + insque(image, &team->image_queue); + } + + RELEASE_TEAM_LOCK(); + restore_interrupts(state); + + dprintf("register_image(team = %ld, image id = %ld, image = %p\n", teamID, id, image); + return id; +} + + +/** Unregisters an image from the specified team. + */ + +status_t +unregister_image(team_id teamID, image_id id) +{ + status_t status = B_ENTRY_NOT_FOUND; + struct image *image; + struct team *team; + cpu_status state; + + state = disable_interrupts(); + GRAB_TEAM_LOCK(); + + team = team_get_team_struct_locked(teamID); + if (team) { + kqueue_foreach (&team->image_queue, image) { + if (image->info.id == id) { + remque(image); + free(image); + status = B_OK; + break; + } + } + } + + RELEASE_TEAM_LOCK(); + restore_interrupts(state); + + 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) +{ + struct image *image; + int32 count = 0; + + kqueue_foreach (&team->image_queue, image) { + 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) +{ + struct image *image, *nextImage; + + ASSERT(team != NULL); + + // can't use kqueue_foreach() because "image" gets freed + for (image = (struct image *)team->image_queue.next; + image != (void *)&team->image_queue; image = nextImage) { + nextImage = image->next; + + free(image); + } +} + + +status_t +_get_image_info(image_id id, image_info *info, size_t size) +{ + status_t status = B_ENTRY_NOT_FOUND; + struct image *image; + struct team *team; + cpu_status state; + + state = disable_interrupts(); + GRAB_TEAM_LOCK(); + + team = thread_get_current_thread()->team; + if (team) { + kqueue_foreach (&team->image_queue, image) { + if (image->info.id == id) { + memcpy(info, &image->info, size); + status = B_OK; + break; + } + } + } + + RELEASE_TEAM_LOCK(); + restore_interrupts(state); + + 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 image *image; + struct team *team; + cpu_status state; + + state = disable_interrupts(); + GRAB_TEAM_LOCK(); + + team = team_get_team_struct_locked(teamID); + if (team) { + int32 count = 0; + kqueue_foreach (&team->image_queue, image) { + 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); + + return status; +} + + +// #pragma mark - +// Functions exported for the user space + + +status_t +user_unregister_image(image_id id) +{ + return unregister_image(team_get_current_team_id(), id); +} + + +image_id +user_register_image(image_info *userInfo, size_t size) +{ + image_info info; + + if (size != sizeof(image_info)) + return B_BAD_VALUE; + + if (!CHECK_USER_ADDRESS(userInfo) + || user_memcpy(&info, userInfo, size) < B_OK) + return B_BAD_ADDRESS; + + return register_image(team_get_current_team_id(), &info, size); +} + + +status_t +user_get_image_info(image_id id, image_info *userInfo, size_t size) +{ + image_info info; + status_t status; + + if (size != sizeof(image_info)) + return B_BAD_VALUE; + + if (!CHECK_USER_ADDRESS(userInfo)) + 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 +user_get_next_image_info(team_id team, int32 *_cookie, image_info *userInfo, size_t size) +{ + image_info info; + status_t status; + + if (size != sizeof(image_info)) + return B_BAD_VALUE; + + if (!CHECK_USER_ADDRESS(userInfo) || !CHECK_USER_ADDRESS(_cookie)) + 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; +} +