aboutsummaryrefslogtreecommitdiff
path: root/kernel/drivers/memdevs.c
blob: 065fde8898c8678e02f5faee98781e53254e5756 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "errno.h"
#include "globals.h"

#include "util/debug.h"
#include "util/string.h"

#include "mm/kmalloc.h"
#include "mm/mobj.h"

#include "drivers/chardev.h"

#include "vm/anon.h"

#include "fs/vnode.h"

static ssize_t null_read(chardev_t *dev, size_t pos, void *buf, size_t count);

static ssize_t null_write(chardev_t *dev, size_t pos, const void *buf,
                          size_t count);

static ssize_t zero_read(chardev_t *dev, size_t pos, void *buf, size_t count);

static long zero_mmap(vnode_t *file, mobj_t **ret);

chardev_ops_t null_dev_ops = {.read = null_read,
                              .write = null_write,
                              .mmap = NULL,
                              .fill_pframe = NULL,
                              .flush_pframe = NULL};

chardev_ops_t zero_dev_ops = {.read = zero_read,
                              .write = null_write,
                              .mmap = zero_mmap,
                              .fill_pframe = NULL,
                              .flush_pframe = NULL};

/**
 * The char device code needs to know about these mem devices, so create
 * chardev_t's for null and zero, fill them in, and register them.
 *
 * Use kmalloc, MEM_NULL_DEVID, MEM_ZERO_DEVID, and chardev_register.
 * See dev.h for device ids to use with MKDEVID.
 */
void memdevs_init()
{
    // NOT_YET_IMPLEMENTED("DRIVERS: memdevs_init");

    // create chardev_t's for null and zero
    chardev_t *null_dev = kmalloc(sizeof(chardev_t));
    if (null_dev == NULL)
    {
        dbg(DBG_DISK, "ERROR: kmalloc failed on null_dev in memdevs_init\n");
        return;
    }
    chardev_t *zero_dev = kmalloc(sizeof(chardev_t));
    if (zero_dev == NULL)
    {
        dbg(DBG_DISK, "ERROR: kmalloc failed on zero_dev in memdevs_init\n");
        return;
    }

    // fill them in
    null_dev->cd_id = MEM_NULL_DEVID;
    null_dev->cd_ops = &null_dev_ops;
    zero_dev->cd_id = MEM_ZERO_DEVID;
    zero_dev->cd_ops = &zero_dev_ops;

    // register them
    chardev_register(null_dev);
    chardev_register(zero_dev);
}

/**
 * Reads a given number of bytes from the null device into a
 * buffer. Any read performed on the null device should read 0 bytes.
 *
 * @param  dev   the null device
 * @param  pos   the offset to read from; should be ignored
 * @param  buf   the buffer to read into
 * @param  count the maximum number of bytes to read
 * @return       the number of bytes read, which should be 0
 */
static ssize_t null_read(chardev_t *dev, size_t pos, void *buf, size_t count)
{
    // NOT_YET_IMPLEMENTED("DRIVERS: null_read");
    // TODO: ask about buffer checking
    return 0; // return reading no bytes
}

/**
 * Writes a given number of bytes to the null device from a
 * buffer. Writing to the null device should _ALWAYS_ be successful
 * and write the maximum number of bytes.
 *
 * @param  dev   the null device
 * @param  pos   offset the offset to write to; should be ignored
 * @param  buf   buffer to read from
 * @param  count the maximum number of bytes to write
 * @return       the number of bytes written, which should be `count`
 */
static ssize_t null_write(chardev_t *dev, size_t pos, const void *buf,
                          size_t count)
{
    // NOT_YET_IMPLEMENTED("DRIVERS: null_write");

    // check if the buffer is NULL
    if (buf == NULL)
    {
        return -EINVAL;
    }

    // there is no true writing, so just do nothing here

    // return the number of bytes written
    return count;
}

/**
 * Reads a given number of bytes from the zero device into a
 * buffer. Any read from the zero device should be a series of zeros.
 *
 * @param  dev   the zero device
 * @param  pos   the offset to start reading from; should be ignored
 * @param  buf   the buffer to write to
 * @param  count the maximum number of bytes to read
 * @return       the number of bytes read. Hint: should always read the maximum
 *               number of bytes
 */
static ssize_t zero_read(chardev_t *dev, size_t pos, void *buf, size_t count)
{
    // NOT_YET_IMPLEMENTED("DRIVERS: zero_read");

    // check if the buffer is NULL
    if (buf == NULL)
    {
        return -EINVAL;
    }

    // fill the buffer with zeros
    memset(buf, 0, count);

    // return the number of bytes read
    return count;
}

/**
 * Unlike in s5fs_mmap(), you can't necessarily use the file's underlying mobj.
 * Instead, you should simply provide an anonymous object to ret.
 */
static long zero_mmap(vnode_t *file, mobj_t **ret)
{
    // NOT_YET_IMPLEMENTED("VM: zero_mmap");

    // create a new anonymous object
    mobj_t *mobj = anon_create();
    mobj_unlock(mobj); // unlock the object from the init
    if (mobj == NULL)
    {
        return -ENOMEM;
    }

    // set the return value
    *ret = mobj;
    return 0;
}