/** Append data to the currently open log entry. * * This function requires that the log_lock is acquired by the caller. */ static void log_append(const uint8_t *data, size_t len) { /* Cap the length so that the entry entirely fits into the buffer */ if (len > LOG_LENGTH - log_current_len) { len = LOG_LENGTH - log_current_len; } if (len == 0) return; size_t log_free = LOG_LENGTH - log_used - log_current_len; /* Discard older entries to make space, if necessary */ while (len > log_free) { size_t entry_len; log_copy_from((uint8_t *) &entry_len, log_start, sizeof(size_t)); log_start = (log_start + entry_len) % LOG_LENGTH; log_used -= entry_len; log_free += entry_len; next_for_uspace -= entry_len; } size_t pos = (log_current_start + log_current_len) % LOG_LENGTH; log_copy_to(data, pos, len); log_current_len += len; }
/** Control of the log from uspace * */ sysarg_t sys_klog(sysarg_t operation, void *buf, size_t size, sysarg_t level) { char *data; int rc; if (size > PAGE_SIZE) return (sysarg_t) ELIMIT; switch (operation) { case KLOG_WRITE: data = (char *) malloc(size + 1, 0); if (!data) return (sysarg_t) ENOMEM; rc = copy_from_uspace(data, buf, size); if (rc) { free(data); return (sysarg_t) rc; } data[size] = 0; if (level >= LVL_LIMIT) level = LVL_NOTE; log(LF_USPACE, level, "%s", data); free(data); return EOK; case KLOG_READ: data = (char *) malloc(size, 0); if (!data) return (sysarg_t) ENOMEM; size_t entry_len = 0; size_t copied = 0; rc = EOK; spinlock_lock(&log_lock); while (next_for_uspace < log_used) { size_t pos = (log_start + next_for_uspace) % LOG_LENGTH; log_copy_from((uint8_t *) &entry_len, pos, sizeof(size_t)); if (entry_len > PAGE_SIZE) { /* * Since we limit data transfer * to uspace to a maximum of PAGE_SIZE * bytes, skip any entries larger * than this limit to prevent * userspace being stuck trying to * read them. */ next_for_uspace += entry_len; continue; } if (size < copied + entry_len) { if (copied == 0) rc = EOVERFLOW; break; } log_copy_from((uint8_t *) (data + copied), pos, entry_len); copied += entry_len; next_for_uspace += entry_len; } spinlock_unlock(&log_lock); if (rc != EOK) { free(data); return (sysarg_t) rc; } rc = copy_to_uspace(buf, data, size); free(data); if (rc != EOK) return (sysarg_t) rc; return copied; default: return (sysarg_t) ENOTSUP; } }