The Pedigree Project 0.1
VirtioBlkDisk.cc
1/* Copyright (c) 2026, Pedigree Developers. SPDX-License-Identifier: ISC */
2#include "VirtioBlkDisk.h"
3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/TargetInfo.h"
5#include "pedigree/kernel/utilities/utility.h"
6
7#include "VirtioBlkController.h"
8
9VirtioBlkDisk::VirtioBlkDisk(VirtioBlkController* controller) : m_Controller(controller) {
10 m_pParent = controller;
11 setSpecificType(String("virtio-blk-disk"));
12}
13
14VirtioBlkDisk::~VirtioBlkDisk() {
17}
18
20 name.assign("Virtio Block Disk");
21}
22
23size_t VirtioBlkDisk::getSize() const {
24 return m_Controller->sizeBytes();
25}
26
27size_t VirtioBlkDisk::getBlockCount() const {
28 return getSize() / getNativeBlockSize();
29}
30
33}
34
36 return m_Controller->sectorBytes();
37}
38
39bool VirtioBlkDisk::writeFrom(uint64_t location, const void* buffer, size_t length) {
40 if (m_Controller->readOnly()) {
41 return !length && location <= getSize();
42 }
43 return ScsiDisk::writeFrom(location, buffer, length);
44}
45
46bool VirtioBlkDisk::writeFromBatch(WriteBuffer* buffers, size_t count) {
47 if (m_Controller->readOnly()) {
48 for (size_t i = 0; buffers && i < count; ++i) {
49 buffers[i].complete = false;
50 }
51 return !count;
52 }
53 return ScsiDisk::writeFromBatch(buffers, count);
54}
55
56void VirtioBlkDisk::write(uint64_t location) {
57 if (!m_Controller->readOnly()) {
58 ScsiDisk::write(location);
59 }
60}
61
62bool VirtioBlkDisk::zero(uint64_t location, size_t length) {
63 return m_Controller->readOnly() ? (!length && location <= getSize())
64 : ScsiDisk::zero(location, length);
65}
66
67BufferView VirtioBlkDisk::acquireView(uint64_t location, bool writable, uint64_t& token) {
68 if (writable && m_Controller->readOnly()) {
69 return {};
70 }
71 return ScsiDisk::acquireView(location, writable, token);
72}
73
74size_t VirtioBlkDisk::validPageLength(uint64_t location) const {
75 const size_t native = getNativeBlockSize();
76 if (!native || location >= getSize() || location % native) {
77 return 0;
78 }
79 const size_t remaining = getSize() - location;
80 const size_t page = TargetInfo::getPageSize();
81 return remaining < page ? remaining : page;
82}
83
84uint64_t VirtioBlkDisk::doRead(uint64_t location) {
85 const size_t bytes = getCacheFillLength(location);
86 if (!bytes || bytes % getNativeBlockSize()) {
87 return 0;
88 }
89 const uintptr_t existing = getCache().lookup(location);
90 if (existing) {
91 getCache().release(location);
92 return bytes;
93 }
94 bool existed = false;
95 const uintptr_t page = getCache().insert(location, &existed);
96 if (!page) {
97 return 0;
98 }
99 if (existed) {
100 return bytes;
101 }
102 ByteSet(reinterpret_cast<void*>(page), 0, TargetInfo::getPageSize());
103 if (!m_Controller->readWrite(location, reinterpret_cast<void*>(page), bytes, false)) {
104 if (!getCache().discardEditing(location)) {
105 FATAL("Virtio block: failed to discard incomplete cache fill");
106 }
107 return 0;
108 }
109 getCache().markNoLongerEditing(location);
110 return bytes;
111}
112
113uint64_t VirtioBlkDisk::doWrite(uint64_t location) {
114#if CRIPPLE_HDD
115 return 0;
116#else
117 if (m_Controller->readOnly() || !validPageLength(location)) {
118 return 0;
119 }
120 const uintptr_t page = getCache().lookup(location);
121 if (!page) {
122 return 0;
123 }
124 CachePageGuard guard(getCache(), location);
125 return doWriteDirect(location, page);
126#endif
127}
128
129uint64_t VirtioBlkDisk::doWriteDirect(uint64_t location, uintptr_t page) {
130#if CRIPPLE_HDD
131 return 0;
132#else
133 const size_t bytes = validPageLength(location);
134 if (m_Controller->readOnly() || !page || !bytes) {
135 return 0;
136 }
137 return m_Controller->readWrite(location, reinterpret_cast<void*>(page), bytes, true) ? bytes : 0;
138#endif
139}
140
141uint64_t VirtioBlkDisk::doSync(uint64_t location) {
142#if CRIPPLE_HDD
143 return 0;
144#else
145 const size_t bytes = location == SyncWholeDevice ? size_t{1} : validPageLength(location);
146 return bytes && m_Controller->flush() ? bytes : 0;
147#endif
148}
149
150bool VirtioBlkDisk::transferBuffer(uint64_t location, void* buffer, size_t length, bool writing) {
151#if CRIPPLE_HDD
152 if (writing) {
153 return false;
154 }
155#endif
156 const size_t native = getNativeBlockSize();
157 if (!buffer || !length || length > TargetInfo::getPageSize() || location >= getSize() ||
158 length > getSize() - location || !native || location % native || length % native ||
159 (writing && m_Controller->readOnly())) {
160 return false;
161 }
162 return m_Controller->readWrite(location, buffer, length, writing);
163}
void release(uintptr_t key)
Definition Cache.cc:1515
uintptr_t insert(uintptr_t key, bool *alreadyExisted=nullptr)
Definition Cache.cc:871
void markNoLongerEditing(uintptr_t key, size_t length=0)
Definition Cache.cc:2587
uintptr_t lookup(uintptr_t key)
Definition Cache.cc:718
void retireEndpoint()
Definition Disk.cc:133
virtual void write(uint64_t location)
Definition ScsiDisk.cc:919
size_t getCacheFillLength(uint64_t location) const
Definition ScsiDisk.cc:1387
bool writeFromBatch(WriteBuffer *buffers, size_t count) override
Definition ScsiDisk.cc:839
bool zero(uint64_t location, size_t length) override
Definition ScsiDisk.cc:664
void shutdownCache()
Definition ScsiDisk.cc:268
static constexpr size_t getPageSize() noexcept
Definition TargetInfo.h:40
void write(uint64_t location) override
size_t getSize() const override
Gets the size of the disk.
size_t getNativeBlockSize() const override
bool writeFromBatch(WriteBuffer *buffers, size_t count) override
uint64_t doWriteDirect(uint64_t location, uintptr_t page) override
void getName(String &name) override
bool zero(uint64_t location, size_t length) override
size_t getBlockSize() const override
Gets the preferred I/O extent of the disk.