Skip to content

Commit 13fabf5

Browse files
authored
Merge pull request #20 from ntoskrnl7/features/ntl
Features/ntl
2 parents e2fb5cc + ee1dbec commit 13fabf5

File tree

18 files changed

+1113
-585
lines changed

18 files changed

+1113
-585
lines changed

README.md

Lines changed: 174 additions & 195 deletions
Large diffs are not rendered by default.

docs/ko-kr.md

Lines changed: 346 additions & 0 deletions
Large diffs are not rendered by default.

include/.internal/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ Environment:
2626

2727
#define CRTSYS_VERSION_MAJOR 0
2828
#define CRTSYS_VERSION_MINOR 1
29-
#define CRTSYS_VERSION_PATCH 6
29+
#define CRTSYS_VERSION_PATCH 7
3030

3131
#endif // _CRTSYS_VERSION_

include/ntl/device

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/**
2+
* @file device
3+
* @author jungkwang.lee ([email protected])
4+
* @brief
5+
*
6+
* @copyright Copyright (c) 2022 NT Template Library Authoers.
7+
*
8+
*/
9+
#pragma once
10+
11+
#include "except"
12+
#include <functional>
13+
#include <stdexcept>
14+
#include <string>
15+
16+
#ifndef _NTDDK_
17+
#include <wdm.h>
18+
#endif
19+
20+
namespace ntl {
21+
class device {
22+
friend class device_dispatch_invoker;
23+
24+
public:
25+
using on_device_control_fn = std::function<void(uint32_t, const uint8_t *,
26+
size_t, uint8_t *, size_t *)>;
27+
28+
private:
29+
friend class driver;
30+
31+
struct context_base {
32+
context_base(const std::type_info &type) : type(type) {}
33+
const std::type_info &type;
34+
on_device_control_fn on_device_control;
35+
};
36+
37+
template <typename T> class context;
38+
39+
template <> struct context<void> : public context_base {
40+
context() : context_base(typeid(void)) {}
41+
};
42+
43+
template <typename T> struct context : public context_base {
44+
context() : context_base(typeid(T)) {}
45+
T data;
46+
};
47+
48+
public:
49+
using type_t = DEVICE_TYPE;
50+
51+
class options {
52+
friend class driver;
53+
friend class device;
54+
55+
public:
56+
options() : type_(FILE_DEVICE_UNKNOWN), exclusive_(false) {}
57+
58+
options &name(const std::wstring &name) {
59+
name_ = name;
60+
return *this;
61+
}
62+
options &type(type_t type) {
63+
type_ = type;
64+
return *this;
65+
}
66+
options &exclusive(bool exclusive = true) {
67+
exclusive_ = exclusive;
68+
return *this;
69+
}
70+
71+
private:
72+
bool exclusive_;
73+
std::wstring name_;
74+
type_t type_;
75+
};
76+
77+
protected:
78+
device(PDEVICE_OBJECT device, const options &opts,
79+
std::function<void()> finalizer)
80+
: object_(device), name_(opts.name_), finalizer_(finalizer) {}
81+
82+
private:
83+
device(const device &) = delete;
84+
85+
public:
86+
device() : object_(nullptr) {}
87+
88+
device(device &&other) { *this = std::move(other); }
89+
90+
device &operator=(device &&rhs) {
91+
object_ = rhs.detach();
92+
name_.swap(rhs.name_);
93+
finalizer_ = std::move(rhs.finalizer_);
94+
return *this;
95+
}
96+
97+
~device() {
98+
auto obj = detach();
99+
if (obj) {
100+
if (finalizer_)
101+
finalizer_();
102+
IoDeleteDevice(obj);
103+
}
104+
}
105+
106+
private:
107+
template <typename Extension> context<Extension> *get_context() {
108+
return reinterpret_cast<context<Extension> *>(object_->DeviceExtension);
109+
}
110+
111+
public:
112+
template <typename Extension> Extension &extension() {
113+
auto ext = get_context<Extension>();
114+
if (ext->type != typeid(Extension))
115+
throw std::runtime_error("bad type");
116+
return ext->data;
117+
}
118+
119+
device &on_device_control(on_device_control_fn &&f) {
120+
get_context<void>()->on_device_control = f;
121+
return *this;
122+
}
123+
124+
const std::wstring &name() const {
125+
if (!object_)
126+
throw std::runtime_error("invalid device object.");
127+
return name_;
128+
}
129+
130+
type_t type() const {
131+
if (!object_)
132+
throw std::runtime_error("invalid device object.");
133+
return object_->DeviceType;
134+
}
135+
136+
PDEVICE_OBJECT detach() {
137+
return reinterpret_cast<PDEVICE_OBJECT>(
138+
InterlockedExchangePointer(reinterpret_cast<PVOID *>(&object_), NULL));
139+
}
140+
141+
private:
142+
PDEVICE_OBJECT object_;
143+
std::wstring name_;
144+
std::function<void()> finalizer_;
145+
};
146+
} // namespace ntl

include/ntl/driver

Lines changed: 77 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -11,128 +11,109 @@
1111
#ifndef _NTDDK_
1212
#include <wdm.h>
1313
#endif
14+
#ifndef ClearFlag
15+
#define ClearFlag(_F, _SF) ((_F) &= ~(_SF))
16+
#endif
17+
18+
#include "device"
19+
#include "except"
1420
#include "status"
21+
#include "unicode_string"
22+
#include <algorithm>
1523
#include <functional>
16-
#include <string>
24+
#include <memory>
25+
#include <unordered_map>
1726

1827
namespace ntl {
19-
class unicode_string {
20-
public:
21-
unicode_string(std::wstring &&str) : str_(std::move(str)) {
22-
value_.Buffer = &str_[0];
23-
value_.MaximumLength = value_.Length = (USHORT)str_.size() * sizeof(WCHAR);
24-
}
25-
unicode_string(const std::wstring &str) : str_(str) {
26-
value_.Buffer = &str_[0];
27-
value_.MaximumLength = value_.Length = (USHORT)str_.size() * sizeof(WCHAR);
28-
}
29-
unicode_string(std::wstring &str) {
30-
value_.Buffer = &str[0];
31-
value_.MaximumLength = value_.Length = (USHORT)str.size() * sizeof(WCHAR);
32-
}
33-
34-
UNICODE_STRING &operator*() { return value_; }
35-
36-
private:
37-
std::wstring str_;
38-
UNICODE_STRING value_;
39-
};
40-
41-
class device {
42-
friend class driver;
43-
44-
public:
45-
using type = ULONG;
46-
47-
protected:
48-
device(PDEVICE_OBJECT device) : object_(device) {}
49-
50-
private:
51-
device(const device &) = delete;
52-
53-
public:
54-
device() : object_(NULL) {}
55-
56-
device(device &&other) { *this = std::move(other); }
57-
58-
device &operator=(device &&rhs) {
59-
object_ = rhs.object_;
60-
rhs.object_ = NULL;
61-
return *this;
62-
}
63-
64-
~device() {
65-
if (object_)
66-
IoDeleteDevice(object_);
67-
}
68-
69-
public:
70-
PDEVICE_OBJECT detach() {
71-
return (PDEVICE_OBJECT)InterlockedExchangePointer((PVOID *)&object_, NULL);
28+
namespace detail {
29+
namespace driver {
30+
inline ntl::except make_exception(NTSTATUS status) {
31+
const char *message;
32+
switch (status) {
33+
case STATUS_INSUFFICIENT_RESOURCES:
34+
message = " Insufficient system resources exist to complete the API.";
35+
break;
36+
case STATUS_OBJECT_NAME_COLLISION:
37+
message = "Object Name already exists.";
38+
break;
39+
default:
40+
message = "Unknown error.";
41+
break;
7242
}
73-
74-
#ifdef NTL_EXPORT_OBJECT_PTR
75-
public:
76-
#else
77-
protected:
78-
#endif
79-
PDEVICE_OBJECT ptr() const { return object_; }
80-
81-
private:
82-
PDEVICE_OBJECT object_;
83-
};
43+
return std::move(ntl::except(status, message));
44+
}
45+
} // namespace driver
46+
} // namespace detail
8447

8548
class driver {
86-
public:
49+
friend class driver_initializer;
8750
friend class driver_unload_invoker;
88-
friend class device_dispatch_invoker;
89-
90-
using unload_routine = std::function<void()>;
91-
92-
using devcie_control_routine =
93-
std::function<void(uint32_t, const uint8_t *, size_t, uint8_t *, size_t *)>;
9451

52+
private:
9553
driver(PDRIVER_OBJECT driver)
9654
: object_(driver), name_(driver->DriverName.Buffer,
9755
driver->DriverName.Length / sizeof(WCHAR)) {}
9856

99-
device create_device(const std::wstring &name, device::type type) {
100-
unicode_string dev_name(L"\\Device\\" + name);
101-
PDEVICE_OBJECT dev = NULL;
102-
status s = IoCreateDevice(object_, 0, &*dev_name, type, 0, FALSE, &dev);
103-
return dev;
104-
}
57+
public:
58+
using unload_routine = std::function<void()>;
59+
60+
using devcie_control_routine = std::function<void(
61+
uint32_t, const uint8_t *, size_t, uint8_t *, size_t *)>;
10562

106-
void on_device_control(devcie_control_routine &&f) {
107-
devcie_control_routine_ = f;
63+
template <typename Extension>
64+
std::shared_ptr<device> create_device(device::options &opts) {
65+
PDEVICE_OBJECT dev = NULL;
66+
status s = [&dev, &opts, this]() {
67+
ULONG extension_size = (ULONG)sizeof(device::context<Extension>);
68+
if (opts.name_.empty()) {
69+
return IoCreateDevice(object_, extension_size, NULL, opts.type_, 0,
70+
opts.exclusive_, &dev);
71+
} else {
72+
unicode_string dev_name(L"\\Device\\" + opts.name_);
73+
return IoCreateDevice(object_, extension_size, &*dev_name, opts.type_,
74+
0, opts.exclusive_, &dev);
75+
}
76+
}();
77+
if (s.is_err())
78+
throw detail::driver::make_exception(s);
79+
80+
new (dev->DeviceExtension) device::context<Extension>();
81+
82+
auto ptr = std::make_shared<device>(std::move(device(dev, opts, [dev]() {
83+
reinterpret_cast<device::context<Extension> *>(dev->DeviceExtension)
84+
->~context();
85+
})));
86+
devices_.insert({dev, ptr});
87+
88+
ClearFlag(dev->Flags, DO_DEVICE_INITIALIZING);
89+
90+
return ptr;
10891
}
10992

11093
void on_unload(unload_routine &&f) { unload_routine_ = f; }
11194

112-
PDRIVER_OBJECT detach() {
113-
return (PDRIVER_OBJECT)InterlockedExchangePointer((PVOID *)&object_, NULL);
95+
std::shared_ptr<device> devices(PDEVICE_OBJECT ptr) noexcept {
96+
try {
97+
return devices_[ptr];
98+
} catch (...) {
99+
return nullptr;
100+
}
101+
};
102+
103+
std::vector<std::shared_ptr<device>> devices() {
104+
std::vector<std::shared_ptr<device>> vec;
105+
std::transform(devices_.begin(), devices_.end(), vec.end(),
106+
[](auto &item) { return item.second; });
107+
return vec;
114108
}
115109

116110
const std::wstring &name() const { return name_; }
117111

118-
#ifdef NTL_EXPORT_OBJECT_PTR
119-
public:
120-
#else
121-
protected:
122-
#endif
123-
PDRIVER_OBJECT ptr() const { return object_; }
124-
125-
private:
126-
void unload() {
127-
if (unload_routine_)
128-
unload_routine_();
129-
}
130-
131112
private:
132113
PDRIVER_OBJECT object_;
133114
std::wstring name_;
134115

135-
devcie_control_routine devcie_control_routine_;
116+
std::unordered_map<PDEVICE_OBJECT, std::shared_ptr<device>> devices_;
136117
unload_routine unload_routine_;
137118
};
138119

include/ntl/expand_stack

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,11 @@ inline ntl::except make_exception(NTSTATUS status) {
115115
const char *message;
116116
switch (status) {
117117
case STATUS_INVALID_PARAMETER_3:
118-
message = "The stack_size parameter is greater than MAXIMUM_EXPANSION_SIZE";
118+
message =
119+
"The stack_size parameter is greater than MAXIMUM_EXPANSION_SIZE.";
119120
break;
120121
case STATUS_INVALID_PARAMETER_4:
121-
message = "The routine was called at IRQL = DISPATCH_LEVEL";
122+
message = "The routine was called at IRQL = DISPATCH_LEVEL.";
122123
break;
123124
case STATUS_NO_MEMORY:
124125
message = "Not enough memory is available to expand the stack.";
@@ -128,7 +129,7 @@ inline ntl::except make_exception(NTSTATUS status) {
128129
"system's internal limits on stack space.";
129130
break;
130131
default:
131-
message = "Unknown error";
132+
message = "Unknown error.";
132133
break;
133134
}
134135
return std::move(ntl::except(status, message));

0 commit comments

Comments
 (0)