Software APIs
status.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/lib/base/status.h"
6
7#include <stdbool.h>
8#include <stdint.h>
9
11
12const uint32_t MODULE_ID = 0;
13
14static const char *basename(const char *file, size_t *basename_len) {
15 const char *f = file;
16 // Go to the end of the string.
17 while (*f)
18 ++f;
19 // Back up to the start of the last filename path component.
20 *basename_len = 0;
21 while (f > file && f[-1] != '/' && f[-1] != '\\') {
22 ++(*basename_len);
23 --f;
24 }
25 return f;
26}
27
28status_t status_from_rom_error(uint32_t val) {
29 uint32_t code =
30 val == kErrorOk ? 0 : bitfield_field32_read(val, ROM_ERROR_FIELD_STATUS);
31 int32_t arg = (int32_t)bitfield_field32_read(val, ROM_ERROR_FIELD_ERROR);
32 uint32_t mod = bitfield_field32_read(val, ROM_ERROR_FIELD_MODULE);
33 uint32_t module = (mod & 0x1F) << 16 | (mod & 0x1F00) << (21 - 8);
34 /* We know that the module ID extracted from the rom_error_t is not undefined
35 * so there is no point in passing a filename to status_created. */
36 return status_create((absl_status_t)code, module, "unk",
37 code == kOk ? kErrorOk : arg);
38}
39
40status_t status_create(absl_status_t code, uint32_t module_id, const char *file,
41 int32_t arg) {
42 if (code == kOk) {
43 if (arg >= 0) {
44 return (status_t){.value = arg};
45 } else {
46 // If you find yourself here, then someone returned a OK_STATUS
47 // a negative value.
48 arg = __LINE__;
49 }
50 }
51 /**
52 * Our status(error) codes are arranged as a packed bitfield:
53 *
54 * 32 31 26 21 16 5 0
55 * +---+-------+-------+-------+-------------+-------+
56 * | | 15 bit | 11 bit | 5 bit |
57 * | s | Module Identifier | Line Number | code |
58 * +---+-------+-------+-------+-------------+-------+
59 *
60 * The sign bit is set on all not-Ok statuses, thus proviging a covenient
61 * overloaded return value from functions that may return an error.
62 */
63 if (module_id == 0) {
64 // First three characters of the filename.
65 size_t basename_len = 0;
66 const char *f = basename(file, &basename_len);
67 module_id = basename_len >= 3 ? MAKE_MODULE_ID(f[0], f[1], f[2])
68 : MAKE_MODULE_ID('u', 'n', 'd');
69 }
70 // The module ID currently encodes one ASCII in each 8-bit field. To make
71 // the three ASCII fit in 15 bits, we convert to 5-bit ASCII characters.
72 module_id = status_encode_module_id(module_id);
73 // At this point, the module_id is already packed into the correct bitfield.
74 return (status_t){
75 .value = (int32_t)(bitfield_field32_write(0, STATUS_FIELD_MODULE_ID,
76 module_id) |
77 bitfield_bit32_write(0, STATUS_BIT_ERROR, true) |
78 bitfield_field32_write(0, STATUS_FIELD_CODE, code) |
79 bitfield_field32_write(0, STATUS_FIELD_ARG,
80 (uint32_t)arg))};
81}
82
83const char *status_codes[] = {
84 "Ok",
85 "Cancelled",
86 "Unknown",
87 "InvalidArgument",
88 "DeadlineExceeded",
89 "NotFound",
90 "AlreadyExists",
91 "PermissionDenied",
92 "ResourceExhausted",
93 "FailedPrecondition",
94 "Aborted",
95 "OutOfRange",
96 "Unimplemented",
97 "Internal",
98 "Unavailable",
99 "DataLoss",
100 "Unauthenticated",
101
102 "Undefined17",
103 "Undefined18",
104 "Undefined19",
105 "Undefined20",
106 "Undefined21",
107 "Undefined22",
108 "Undefined23",
109 "Undefined24",
110 "Undefined25",
111 "Undefined26",
112 "Undefined27",
113 "Undefined28",
114 "Undefined29",
115 "Undefined30",
116 "Undefined31",
117
118 // A "ErrorError" means the error bit is set but the err field is kOk.
119 "ErrorError",
120};
121
122bool status_extract(status_t s, const char **code, int32_t *arg, char *mod_id) {
123 size_t err = (size_t)status_err(s);
124 if (s.value < 0 && err == 0) {
125 err = sizeof(status_codes) / sizeof(status_codes[0]) - 1;
126 }
127 *code = status_codes[err];
128 if (err) {
129 *arg = (int32_t)bitfield_field32_read((uint32_t)s.value, STATUS_FIELD_ARG);
130 uint32_t module_id =
131 bitfield_field32_read((uint32_t)s.value, STATUS_FIELD_MODULE_ID);
132 *mod_id++ = '@' + ((module_id >> 0) & 0x1F);
133 *mod_id++ = '@' + ((module_id >> 5) & 0x1F);
134 *mod_id++ = '@' + ((module_id >> 10) & 0x1F);
135 return true;
136 } else {
137 *arg = s.value;
138 return false;
139 }
140}
141
142extern bool status_ok(status_t s);
143extern absl_status_t status_err(status_t s);
144
145// This is a weak implementation that does nothing. This way it can easily be
146// overidden and does not require every user of status to manually add a
147// dependency.
149void status_report(status_t value) { (void)value; }