Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
atapi.cpp
Go to the documentation of this file.
1#include "ioforge/ioforge.hpp"
3#include "notify.h"
4#include "type.h"
5#include "vfs/dentry.h"
6#include "vfs/dev.h"
7#include "vfs/vfs.h"
8#include "vfs/vnode.h"
9#include <atapi/atapi.hpp>
10#include <str.h>
11
12typedef struct {
15} __attribute__((packed)) read_capacity10_resp_t;
16
18 uint32_t sector_count, uint8_t (&acmd)[16]) {
19 acmd[0] = opcode;
20 acmd[1] = 0;
21 acmd[2] = (lba >> 24) & 0xFF;
22 acmd[3] = (lba >> 16) & 0xFF;
23 acmd[4] = (lba >> 8) & 0xFF;
24 acmd[5] = (lba >> 0) & 0xFF;
25
26 if (opcode == 0xA8 || opcode == 0xAA) {
27 // READ(12) / WRITE(12) - Transfer Length is 4 bytes at [6..9]
28 acmd[6] = (sector_count >> 24) & 0xFF;
29 acmd[7] = (sector_count >> 16) & 0xFF;
30 acmd[8] = (sector_count >> 8) & 0xFF;
31 acmd[9] = (sector_count >> 0) & 0xFF;
32 acmd[10] = 0;
33 acmd[11] = 0;
34 } else {
35 // READ(10) / WRITE(10) - Transfer Length is 2 bytes at [7..8]
36 acmd[6] = 0;
37 acmd[7] = (sector_count >> 8) & 0xFF;
38 acmd[8] = (sector_count >> 0) & 0xFF;
39 acmd[9] = 0;
40 acmd[10] = 0;
41 acmd[11] = 0;
42 }
43}
44
45void ATAPIModule::probe(struct ioforge_block_device* block) { identify(block); }
46
48 uintptr_t resp_phys = 0;
49
50 read_capacity10_resp_t* resp =
51 (read_capacity10_resp_t*)IOUtils::DMAAlloc(sizeof(*resp),
52 &resp_phys);
53
54 memset(resp, 0, sizeof(*resp));
55
56 uint8_t packet[12] = {0x25};
57
58 struct ioforge_block_request cap_req = {
60 .lba = 0,
61 .buffer = (void*)resp_phys,
62 .buffer_size = sizeof(*resp),
63 .block_count = 1,
64 .flags = IOFORGE_FLAG_DMA,
65 .packet_cmd = packet,
66 .packet_cmd_len = 12,
67 .timeout_ms = 5000,
68 };
69
70 if (!block->ops.submit(block, &cap_req)) {
71 log(mod, "failed to idenitify device");
72 }
73
74 block->sector_size = __builtin_bswap32(resp->block_size);
75 log(mod, "sector size %d", block->sector_size);
76 IOUtils::DMAFree((void*)resp_phys, (void*)resp, sizeof(*resp));
77}
78
80 uintptr_t buff_phys = 0;
81 uint16_t* buff = (uint16_t*)IOUtils::DMAAlloc(512, &buff_phys);
82 memset(buff, 0, 512);
83
84 struct ioforge_block_request req = {
86 .lba = 0,
87 .buffer = (void*)buff_phys,
88 .buffer_size = 512,
89 .block_count = 1,
91 .packet_cmd = 0,
92 .packet_cmd_len = 10,
93 .timeout_ms = 5000,
94 };
95
96 if (!block->ops.submit(block, &req)) {
97 log(mod, "failed to idenitify device");
98 IOUtils::DMAFree((void*)buff_phys, (void*)buff, 512);
99 return;
100 }
101
102 uint16_t info = buff[0];
103 if (info & (1 << 15)) {
104 log(mod, "ATAPI Device");
105 }
106 uint8_t method = (info & (0b1100000)) >> 5;
107 log(mod, "method %b", method);
108
109 uint16_t command_set_supported = buff[83] & 0b111;
110 log(mod, "supported : %b", command_set_supported);
111
112 char serial_number[21] = {0};
113 read_ascii(serial_number, 10, buff, 20);
114 log(mod, "serial number: %s", (char*)serial_number);
115
116 char firmware_version[9] = {0};
117 read_ascii(firmware_version, 23, buff, 8);
118 log(mod, "firmware version: %s", (char*)firmware_version);
119
120 char* model_number = (char*)kalloc(41);
121 memset(model_number, 0, 41);
122 read_ascii(model_number, 27, buff, 40);
123 log(mod, "model number: %s", (char*)model_number);
124 block->model_number = str(model_number);
125 kfree2(model_number);
126
127 // setup node
128 uint16_t cmd_f_supported = buff[82];
129 log(mod, "cmd_f_supported: %b", cmd_f_supported);
130
131 uint16_t ata_version = (buff[80] & 0x1F) >> 1;
132 log(mod, "ata_version support: %b", ata_version);
133
134 log(mod, "block 0x%x", block);
135
136 // read capacity
137 read_sector_size(block);
138
139 {
140 // TODO: create this path dynamically cd0
141 dentry_ptr dentry = 0;
142 vxnamei("/dev/cd0", &dentry);
144 dentry->vnode = vnode;
146 vnode->permission = 666;
147 serial2_printf("dentry namei done\n");
148
149 vops_blk_t* vops = (vops_blk_t*)kalloc(sizeof(vops_blk_t));
150 vops->open = 0;
151 vops->read = ATAPIModule::read;
153 vops->v_data = block;
154 vnode->ops = (void*)vops;
155
156 auto cdev = create_dev(vops, DEV_MAJOR_CDROM);
157 if (!cdev)
158 return;
161
162 notify_call((char*)"/vfs/block", VFS_NOTIFY_PROBE,
163 (void*)dentry);
164 }
165 log(mod, "block 0x%x", block);
166
167 IOUtils::DMAFree((void*)buff_phys, (void*)buff, 512);
168}
169
170extern "C" int ATAPIModule::read(vnode_t* vnode, uintptr_t addr, void* buf,
171 size_t count) {
172 auto i = ATAPIModule::getInstance();
173
174 auto vops = (vops_blk_t*)vnode->ops;
175 if (!vops) {
176 log(i->mod, "read: vops is null");
177 return -EINVAL;
178 }
179
180 struct ioforge_block_device* block =
181 (struct ioforge_block_device*)vops->v_data;
182 if (!block) {
183 log(i->mod, "read: block device is null");
184 return -EINVAL;
185 }
186
187 if (!buf || count == 0) {
188 log(i->mod, "read: invalid buffer or count");
189 return -EINVAL;
190 }
191
192 const size_t sector_size =
193 block->sector_size ? block->sector_size : 2048;
194 // uint32_t lba = (uint32_t)(addr / sector_size);
195 uint32_t lba = (uint32_t)addr;
196 uint16_t sector_count =
197 (uint16_t)((count + sector_size - 1) / sector_size);
198
199 uintptr_t buff_phys;
200 void* buff_ = IOUtils::DMAAlloc(sector_count * sector_size, &buff_phys);
201 if (!buff_) {
202 log(i->mod, "read: DMA alloc failed");
203 return -2;
204 }
205 memset(buff_, 0, sector_count * sector_size);
206
207 uint8_t acmd[16] = {0};
208 i->build_acmd(0xA8, lba, sector_count, acmd);
209
210 struct ioforge_block_request req = {
212 .lba = lba,
213 .buffer = (void*)buff_phys,
214 .buffer_size = sector_count * sector_size,
215 .block_count = sector_count,
217 .packet_cmd = acmd,
218 .packet_cmd_len = 12,
219 .timeout_ms = 5000,
220 };
221
222 int ret = block->ops.submit(block, &req);
223 if (!ret) {
224 log(i->mod, "read: submit failed (lba=%d, sectors=%d)", lba,
225 sector_count);
226 IOUtils::DMAFree((void*)buff_phys, buff_,
227 sector_count * sector_size);
228 return -1;
229 }
230
231 memcopy(buf, buff_, count);
232
233 IOUtils::DMAFree((void*)buff_phys, buff_, sector_count * sector_size);
234
235 log(i->mod, "read: success (lba=%d, sectors=%d)", lba, sector_count);
236 return (int)count;
237}
238
239extern "C" int ATAPIModule::write(vnode_t* vnode, uintptr_t addr, void* buf,
240 size_t count) {
241 auto i = ATAPIModule::getInstance();
242 auto vops = (vops_blk_t*)vnode->ops;
243 if (!vops) {
244 log(i->mod, "read: vops is null");
245 return -EINVAL;
246 }
247
248 struct ioforge_block_device* block =
249 (struct ioforge_block_device*)vops->v_data;
250 if (!block) {
251 log(i->mod, "write: block device is null");
252 return -EINVAL;
253 }
254
255 if (!buf || count == 0) {
256 log(i->mod, "write: invalid buffer or count");
257 return -EINVAL;
258 }
259
260 // Cek apakah device support write
261 if (!block->ops.submit) {
262 log(i->mod,
263 "write: device is read-only or write not supported");
264 return -EROFS;
265 }
266
267 const size_t sector_size =
268 block->sector_size ? block->sector_size : 2048;
269 uint32_t lba = (uint32_t)(addr / sector_size);
270 uint16_t sector_count =
271 (uint16_t)((count + sector_size - 1) / sector_size);
272
273 uintptr_t buff_phys =
274 (uintptr_t)buf; // ganti virt_to_phys(buf) jika perlu
275 uint8_t acmd[16] = {0};
276 i->build_acmd(0xAA, lba, sector_count, acmd);
277
278 struct ioforge_block_request req = {
280 .lba = lba,
281 .buffer = (void*)buff_phys,
282 .buffer_size = sector_count * sector_size,
283 .block_count = sector_count,
285 .packet_cmd = acmd,
286 .packet_cmd_len = 12,
287 .timeout_ms = 30000,
288 };
289
290 int ret = block->ops.submit(block, &req);
291 if (ret) {
292 log(i->mod, "write: submit failed (lba=%u, count=%u, err=%d)",
293 lba, sector_count, ret);
294 return ret;
295 }
296
297 log(i->mod, "write: success (lba=%u, sectors=%u)", lba, sector_count);
298 return 0;
299}
300
301void ATAPIModule::read_ascii(char* out, uint16_t off, uint16_t* buff,
302 uint16_t len) {
303 memcopy(out, &buff[off], len);
304
305 for (int i = 0; i < len; i += 2) {
306 char temp = out[i];
307 out[i] = out[i + 1];
308 out[i + 1] = temp;
309 }
310
311 for (int i = len - 1; i >= 0; i--) {
312 if (out[i] == ' ') {
313 out[i] = '\0';
314 } else {
315 break;
316 }
317 }
318}
int count
Definition cache.h:2
void identify(struct ioforge_block_device *block)
Definition atapi.cpp:79
static int read(vnode_t *vnode, uintptr_t addr, void *buf, size_t count)
Definition atapi.cpp:170
void read_sector_size(struct ioforge_block_device *block)
Definition atapi.cpp:47
void read_ascii(char *out, uint16_t off, uint16_t *buff, uint16_t len)
Definition atapi.cpp:301
static ATAPIModule * getInstance()
Definition init.cpp:10
void build_acmd(uint8_t opcode, uint32_t lba, uint32_t sector_count, uint8_t(&acmd)[16])
Definition atapi.cpp:17
void probe(struct ioforge_block_device *block)
Definition atapi.cpp:45
static int write(vnode_t *vnode, uintptr_t addr, void *buf, size_t count)
Definition atapi.cpp:239
const char * mod
Definition ioforge.hpp:65
struct dentry * dentry_ptr
Definition dentry.h:20
int vxnamei(const char *path, dentry_ptr *out)
Resolves a file path to a directory entry (dentry).
#define DEV_MAJOR_CDROM
Definition dev.h:40
cdev_ptr_t create_dev(void *ops, uint32_t major)
volatile uint64_t addr
Definition e1000.hpp:0
struct vnode vnode_t
Definition filesystem.h:10
uint16_t flags
Definition thread.h:5
typedef __attribute__
Definition msi.c:47
void serial2_printf(const char *fmt,...)
#define log(mod, fmt,...)
Definition ioforge.hpp:12
#define EINVAL
@ IOFORGE_FLAG_DMA
#define EROFS
@ IOFORGE_BLOCK_OP_PACKET
@ IOFORGE_BLOCK_OP_IDENTIFY
void * kalloc(size_t size)
void kfree2(void *ptr)
int notify_call(char *name, uint32_t event, void *data)
Definition notify.c:110
size_t len
Definition oct2bin.h:7
void memset(void *ptr, int value, size_t num)
void memcopy(void *dest, void *src, size_t size)
kstring str(const char *str)
uint32_t block_size
Definition atapi.cpp:14
uint32_t last_lba
Definition atapi.cpp:13
Definition dev.h:63
uint32_t major
Definition dev.h:64
uint32_t minor
Definition dev.h:65
struct vnode * vnode
Definition dentry.h:33
uint32_t major
Definition vnode.h:55
uint32_t minor
Definition vnode.h:56
struct ioforge_block_op ops
int(* submit)(struct ioforge_block_device *dev, struct ioforge_block_request *req)
Definition vnode.h:59
struct device_id device
Definition vnode.h:73
void * ops
Definition vnode.h:64
uint8_t type
Definition vnode.h:62
uint16_t permission
Definition vnode.h:65
void * v_data
Definition vnode.h:46
int(* write)(vnode_t *vnode, uintptr_t addr, void *buf, size_t count)
Definition vnode.h:44
int(* open)(vnode_t *vnode, int op_mode, thread_t *thread)
Definition vnode.h:42
int(* read)(vnode_t *vnode, uintptr_t addr, void *buf, size_t count)
Definition vnode.h:43
unsigned short uint16_t
Definition type.h:13
unsigned int uint32_t
Definition type.h:19
unsigned long uintptr_t
Definition type.h:73
unsigned char uint8_t
Definition type.h:7
vnode_t * create_and_attach_vnode()
@ VFS_NOTIFY_PROBE
Definition vfs.h:13
@ VNODE_TYPE_BLK
Definition vnode.h:16
struct vops_blk vops_blk_t
uint32_t info
Definition xhci.hpp:0