rewrite the device subsystem interfaces (#48)
[lunaix-os.git] / lunaix-os / kernel / kprint / kprintf.c
1 #include <lunaix/fs/twifs.h>
2 #include <lunaix/fs/twimap.h>
3 #include <lunaix/syscall.h>
4 #include <lunaix/syscall_utils.h>
5 #include <lunaix/syslog.h>
6 #include <lunaix/device.h>
7 #include <lunaix/owloysius.h>
8
9 #include <hal/term.h>
10
11 #include <klibc/strfmt.h>
12
13 #include "kp_records.h"
14
15 #define MAX_BUFSZ 512
16 #define MAX_BUFSZ_HLF 256
17 #define MAX_KPENT_NUM 1024
18
19 static char tmp_buf[MAX_BUFSZ];
20
21 static struct kp_records kprecs = {
22     .kp_ents = { .ents = { .next = &kprecs.kp_ents.ents,
23                            .prev = &kprecs.kp_ents.ents } },
24     .max_recs = MAX_KPENT_NUM,
25     .kp_ent_wp = &kprecs.kp_ents.ents
26 };
27 export_symbol(debug, kprintf, kprecs);
28
29 static char*
30 shift_level(const char* str, int* level)
31 {
32     if (str[0] == KMSG_LVLSTART) {
33         *level = KMSG_LOGLEVEL(str[1]);
34
35         return str += 2;
36     }
37
38     *level = KLOG_INFO;
39     return str;
40 }
41
42 static inline void
43 kprintf_put(int level, const char* buf, size_t sz)
44 {
45     kprec_put(&kprecs, level, buf, sz);
46
47     if (likely(sysconsole)) {
48         sysconsole->ops.write(sysconsole, buf, 0, sz);
49     }
50 }
51
52 static inline void
53 kprintf_ml(const char* component, int level, const char* fmt, va_list args)
54 {
55     char* buf = &tmp_buf[MAX_BUFSZ_HLF];
56     ksnprintf(buf, MAX_BUFSZ_HLF, "%s: %s\n", component, fmt);
57
58     size_t sz = ksnprintfv(tmp_buf, buf, MAX_BUFSZ_HLF, args);
59     kprintf_put(level, tmp_buf, sz);
60 }
61
62 void
63 kprintf_m(const char* component, const char* fmt, va_list args)
64 {
65     int level;
66     fmt = shift_level(fmt, &level);
67
68     kprintf_ml(component, level, fmt, args);
69 }
70
71 void
72 kprintf_v(const char* component, const char* fmt, ...)
73 {
74     va_list args;
75     va_start(args, fmt);
76     kprintf_m(component, fmt, args);
77     va_end(args);
78 }
79
80 static void
81 __twimap_kprintf_read(struct twimap* map)
82 {
83     struct kp_records* __kprecs = twimap_data(map, struct kp_records*);
84
85     /*
86         XXX we can foreach all records in a single twimap read call,
87             as records is monotonic increasing by design.
88     */
89     struct kp_entry *pos, *n;
90     llist_for_each(pos, n, __kprecs->kp_ent_wp, ents)
91     {
92         time_t s = pos->time / 1000;
93         time_t ms = pos->time % 1000;
94         twimap_printf(map, "[%05d.%03d] %s\n", s, ms, pos->content);
95     }
96 }
97
98 static void
99 kprintf_mapping_init()
100 {
101     twimap_entry_simple(NULL, "kmsg", &kprecs, __twimap_kprintf_read);
102 }
103 EXPORT_TWIFS_PLUGIN(kprintf, kprintf_mapping_init);
104
105
106 void 
107 kprintf_dump_logs() {
108     if (unlikely(!sysconsole)) {
109         return;
110     }
111
112     struct kp_entry *pos, *n;
113     llist_for_each(pos, n, kprecs.kp_ent_wp, ents)
114     {
115         sysconsole->ops.write(sysconsole, pos->content, 0, pos->len);
116     }
117 }
118
119 __DEFINE_LXSYSCALL3(void, syslog, int, level, 
120                     const char*, buf, unsigned int, size)
121 {
122     kprintf_put(level, buf, size);
123 }