Skip to content

Commit af68d97

Browse files
committed
* Mm: Add MmMapViewOfObject, MmMapViewOfFile.
We also need to implement this in the page fault handler, and then add tests for it. * Io: Add IoIsSeekable - checks if an I/O file object is mappable/seekable. Devices such as keyboards are not mappable, but block devices and file system backed files are. They're characterized by the fact they can or cannot seek (so, don't have random access), which is an important part of whether a file is pageable. * Ob: Return the pointer to the object when calling ObReferenceObjectByPointer. * Style Guide: Modify the section on parenthesis layout in function declarations.
1 parent 7b556c4 commit af68d97

File tree

15 files changed

+230
-48
lines changed

15 files changed

+230
-48
lines changed

boron/include/io/dispatch.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/***
22
The Boron Operating System
3-
Copyright (C) 2024 iProgramInCpp
3+
Copyright (C) 2024-2025 iProgramInCpp
44
55
Module name:
66
io/dispatch.h
@@ -24,6 +24,10 @@ Module name:
2424
//
2525
// - The BSTATUS returned must have the same value as the value inside the "Status" pointer, if it exists.
2626
//
27+
// - IO_SEEKABLE_METHOD returns whether or not the file is seekable. This is, in this case, equal to whether the file
28+
// is mappable. Block devices and file system backed files should return TRUE, while stream I/O devices such as
29+
// keyboards and serial ports should return FALSE.
30+
//
2731
// - If IsEntryFromReadDir is TRUE, IO_LOOKUP_DIR_METHOD, IO_UNLINK_METHOD and IO_REMOVE_DIR_METHOD may optimize by opening
2832
// the inode/file according to the other fields of the IO_DIRECTORY_ENTRY, instead of performing a potentially expensive
2933
// lookup again on the name. If it is false, the other fields must be IGNORED and the file name must be taken into
@@ -91,6 +95,7 @@ typedef void (*IO_CREATE_OBJ_METHOD) (PFCB Fcb, void* FileObject);
9195
typedef void (*IO_DELETE_METHOD) (PFCB Fcb);
9296
typedef void (*IO_DELETE_OBJ_METHOD) (PFCB Fcb, void* FileObject);
9397
typedef void (*IO_DEREFERENCE_METHOD)(PFCB Fcb);
98+
typedef bool (*IO_SEEKABLE_METHOD) (PFCB Fcb);
9499
typedef BSTATUS(*IO_OPEN_METHOD) (PFCB Fcb, uint32_t OpenFlags);
95100
typedef BSTATUS(*IO_CLOSE_METHOD) (PFCB Fcb, int LastHandleCount);
96101
typedef BSTATUS(*IO_READ_METHOD) (PIO_STATUS_BLOCK Iosb, PFCB Fcb, uint64_t Offset, PMDL MdlBuffer, uint32_t Flags);
@@ -154,6 +159,7 @@ typedef struct _IO_DISPATCH_TABLE
154159
IO_CREATE_OBJ_METHOD CreateObject;
155160
IO_DELETE_OBJ_METHOD DeleteObject;
156161
IO_DEREFERENCE_METHOD Dereference;
162+
IO_SEEKABLE_METHOD Seekable;
157163
IO_OPEN_METHOD Open;
158164
IO_CLOSE_METHOD Close;
159165
IO_READ_METHOD Read;

boron/include/io/fileobj.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,5 @@ typedef struct _FILE_OBJECT
3030
uint32_t OpenFlags;
3131
}
3232
FILE_OBJECT, *PFILE_OBJECT;
33+
34+
bool IoIsSeekable(PFILE_OBJECT Object);

boron/include/mm.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ Module name:
2828
#include <mm/probe.h>
2929
#include <mm/mdl.h>
3030
#include <mm/cache.h>
31-
#include <mm/vad.h>
3231
#include <mm/section.h>
32+
#include <mm/vad.h>
3333
#include <mm/heap.h>
3434
#include <mm/services.h>
3535

boron/include/mm/section.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Module name:
1515

1616
typedef struct
1717
{
18-
18+
// TODO
19+
int X;
1920
}
2021
MMSECTION, *PMMSECTION;

boron/include/mm/vad.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ typedef union
4545

4646
// If this region is private (so, not duplicated across forks for example)
4747
int Private : 1;
48+
49+
// If this region is a file object, as opposed to a section object, or nothing.
50+
int IsFile : 1;
4851
};
4952

5053
uint32_t LongFlags;
@@ -63,11 +66,12 @@ typedef struct _MMVAD_ENTRY
6366
{
6467
void* Object;
6568
PFILE_OBJECT FileObject;
69+
PMMSECTION SectionObject;
6670
}
6771
Mapped;
6872

69-
// If this is a file, then the offset within the file.
70-
uint64_t OffsetInFile;
73+
// If this is a file or section, then the offset within it.
74+
uint64_t SectionOffset;
7175
}
7276
MMVAD, *PMMVAD;
7377

@@ -93,7 +97,7 @@ void MmUnlockVadList(PMMVAD_LIST);
9397
// Looks up a VAD by address in a VAD list previously locked with MmLockVadListProcess.
9498
PMMVAD MmLookUpVadByAddress(PMMVAD_LIST VadList, uintptr_t Address);
9599

96-
// Reserves a bunch of virtual memory and returns an address.
100+
// Reserves a range of virtual memory and returns an address.
97101
BSTATUS MmReserveVirtualMemory(size_t SizePages, void** OutAddress, int AllocationType, int Protection);
98102

99103
// Releases a region of virtual memory.

boron/include/ob.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ BSTATUS ObCreateSymbolicLinkObject(
284284
);
285285

286286
// Adds 1 to the internal reference count of the object.
287-
void ObReferenceObjectByPointer(void* Object);
287+
void* ObReferenceObjectByPointer(void* Object);
288288

289289
// Takes a reference away from the internal ref count of the object.
290290
// If the reference count hits zero, the object will be deleted.

boron/source/io/file.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ Module name:
1313
***/
1414
#include "iop.h"
1515

16+
// Checks if this file is seekable.
17+
bool IoIsSeekable(PFILE_OBJECT FileObject)
18+
{
19+
PFCB Fcb = FileObject->Fcb;
20+
IO_SEEKABLE_METHOD Seekable = Fcb->DispatchTable->Seekable;
21+
22+
if (!Seekable)
23+
return false;
24+
25+
return Seekable(Fcb);
26+
}
27+
1628
// Create a file object. This doesn't actually open the object.
1729
BSTATUS IopCreateFileObject(PFCB Fcb, PFILE_OBJECT* OutObject, uint32_t Flags, uint32_t OpenFlags)
1830
{

boron/source/mm/mi.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,10 @@ PMMPTE MmGetPteLocation(uintptr_t Address);
252252
// been generated if GenerateMissingLevels is true).
253253
bool MmCheckPteLocation(uintptr_t Address, bool GenerateMissingLevels);
254254

255+
// Reserves a range of virtual memory and returns a VAD.
256+
//
257+
// Note: This leaves the VAD list locked, if the function succeeds, so you must call MmUnlockVadList!
258+
// Note: All of the parameters are presumed valid!
259+
BSTATUS MmReserveVirtualMemoryVad(size_t SizePages, int AllocationType, int Protection, PMMVAD* OutVad, PMMVAD_LIST* OutVadList);
260+
255261
#endif//NS64_MI_H

boron/source/mm/vad.c

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,8 @@ void MmInitializeVadList(PMMVAD_LIST VadList)
3838
InitializeRbTree(&VadList->Tree);
3939
}
4040

41-
// Reserves a range of virtual memory.
42-
BSTATUS MmReserveVirtualMemory(size_t SizePages, void** OutAddress, int AllocationType, int Protection)
41+
BSTATUS MmReserveVirtualMemoryVad(size_t SizePages, int AllocationType, int Protection, PMMVAD* OutVad, PMMVAD_LIST* OutVadList)
4342
{
44-
if (Protection & ~(PAGE_READ | PAGE_WRITE | PAGE_EXECUTE))
45-
return STATUS_INVALID_PARAMETER;
46-
47-
if (AllocationType & ~(MEM_RESERVE | MEM_COMMIT | MEM_SHARED | MEM_TOP_DOWN))
48-
return STATUS_INVALID_PARAMETER;
49-
5043
PEPROCESS Process = PsGetCurrentProcess();
5144
PMMADDRESS_NODE AddrNode;
5245

@@ -70,14 +63,33 @@ BSTATUS MmReserveVirtualMemory(size_t SizePages, void** OutAddress, int Allocati
7063
// Clear all the fields in the VAD.
7164
Vad->Flags.LongFlags = 0;
7265
Vad->Mapped.Object = NULL;
73-
Vad->OffsetInFile = 0;
66+
Vad->SectionOffset = 0;
7467
Vad->Flags.Committed = (AllocationType & MEM_COMMIT) != 0;
7568
Vad->Flags.Private = (~AllocationType & MEM_SHARED) != 0;
7669
Vad->Flags.Protection = Protection;
7770

78-
*OutAddress = (void*) Vad->Node.StartVa;
71+
*OutVad = Vad;
72+
*OutVadList = &Process->VadList;
73+
return STATUS_SUCCESS;
74+
}
75+
76+
// Reserves a range of virtual memory.
77+
BSTATUS MmReserveVirtualMemory(size_t SizePages, void** OutAddress, int AllocationType, int Protection)
78+
{
79+
if (Protection & ~(PAGE_READ | PAGE_WRITE | PAGE_EXECUTE))
80+
return STATUS_INVALID_PARAMETER;
7981

80-
MmUnlockVadList(&Process->VadList);
82+
if (AllocationType & ~(MEM_RESERVE | MEM_COMMIT | MEM_SHARED | MEM_TOP_DOWN))
83+
return STATUS_INVALID_PARAMETER;
84+
85+
PMMVAD Vad;
86+
PMMVAD_LIST VadList;
87+
BSTATUS Status = MmReserveVirtualMemoryVad(SizePages, AllocationType, Protection, &Vad, &VadList);
88+
if (FAILED(Status))
89+
return Status;
90+
91+
*OutAddress = (void*) Vad->Node.StartVa;
92+
MmUnlockVadList(VadList);
8193
return STATUS_SUCCESS;
8294
}
8395

@@ -125,35 +137,23 @@ BSTATUS MiReleaseVad(PMMVAD Vad)
125137

126138
MmUnlockSpace(Ipl, Vad->Node.StartVa);
127139

128-
// Step 4. Finally, add the range into the heap/free list.
140+
// Step 4. Remove the reference to the object if needed.
141+
if (Vad->Mapped.Object)
142+
{
143+
ObDereferenceObject(Vad->Mapped.Object);
144+
Vad->Mapped.Object = NULL;
145+
}
146+
147+
// Step 5. Finally, add the range into the heap/free list.
129148
BSTATUS Status = MmFreeAddressSpace(&Process->Heap, &Vad->Node);
130149
if (FAILED(Status))
131150
{
132-
// NOTE: This should never happen. But perhaps it's a good time
133-
// to consider that we should probably own both the VAD list mutex
134-
// and the heap mutex at the same time, with a single
135-
// KeWaitForMultipleObjects call.
151+
// NOTE: This should never happen.
136152
//
137-
// An argument against it is that there's no way for this region
138-
// to be used if it's not part of either the heap or the VAD list.
139-
140-
#ifdef DEBUG
153+
// Why? Because there's no way for this region to be used if it's
154+
// not part of either the heap or the VAD list.
141155
KeCrash("MmDereserveVad: Failed to insert VAD into free-heap (address %p)", Vad->Node.StartVa);
142-
#endif
143-
144-
// Re-insert it?
145-
MiLockVadList(&Process->VadList);
146-
bool Inserted = InsertItemRbTree(&Process->VadList.Tree, &Vad->Node.Entry);
147-
MmUnlockVadList(&Process->VadList);
148-
149-
if (!Inserted)
150-
{
151-
// Ohhh.... crap
152-
#ifdef DEBUG
153-
KeCrash("MmDereserveVad: Unreachable");
154-
#endif
155-
Status = STATUS_UNIMPLEMENTED;
156-
}
156+
Status = STATUS_UNIMPLEMENTED;
157157
}
158158

159159
return Status;

boron/source/mm/view.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/***
2+
The Boron Operating System
3+
Copyright (C) 2025 iProgramInCpp
4+
5+
Module name:
6+
mm/view.c
7+
8+
Abstract:
9+
This module defines functions that map and unmap views
10+
of files or sections into the virtual memory space.
11+
12+
Author:
13+
iProgramInCpp - 3 April 2025
14+
***/
15+
#include "mi.h"
16+
#include <ex.h>
17+
#include <io.h>
18+
19+
// NOTE: AllocationType and Protection have been validated.
20+
BSTATUS MmMapViewOfFile(
21+
PFILE_OBJECT FileObject,
22+
void** BaseAddressOut,
23+
size_t* ViewSizeInOut,
24+
int AllocationType,
25+
uint64_t SectionOffset,
26+
int Protection
27+
)
28+
{
29+
// You cannot map files that are not seekable.
30+
if (!IoIsSeekable(FileObject))
31+
return STATUS_UNSUPPORTED_FUNCTION;
32+
33+
size_t ViewSize = *ViewSizeInOut;
34+
size_t PageOffset = SectionOffset & (PAGE_SIZE - 1);
35+
size_t ViewSizePages = (ViewSize + PageOffset + PAGE_SIZE - 1) / PAGE_SIZE;
36+
37+
PMMVAD Vad;
38+
PMMVAD_LIST VadList;
39+
40+
// Reserve the region, and then mark it as committed ourselves.
41+
BSTATUS Status = MmReserveVirtualMemoryVad(ViewSizePages, AllocationType | MEM_RESERVE, Protection, &Vad, &VadList);
42+
if (FAILED(Status))
43+
return Status;
44+
45+
// Vad Protection and Private are filled in by MmReserveVirtualMemoryVad.
46+
Vad->Flags.Committed = 1;
47+
Vad->Flags.IsFile = 1;
48+
Vad->Mapped.FileObject = ObReferenceObjectByPointer(FileObject);
49+
Vad->SectionOffset = SectionOffset & ~(PAGE_SIZE - 1);
50+
51+
*BaseAddressOut = (void*) Vad->Node.StartVa;
52+
*ViewSizeInOut = PAGE_SIZE * ViewSizePages;
53+
MmUnlockVadList(VadList);
54+
55+
return STATUS_UNIMPLEMENTED;
56+
}
57+
58+
//
59+
// Maps a view of either a file or a section. The type will be checked inside.
60+
// The only supported types of object are MmSectionType and IoFileType.
61+
//
62+
// Parameters:
63+
// MappedObject - The object of which a view is to be mapped.
64+
//
65+
// BaseAddressOut - The base address of the view. If MEM_FIXED is specified, then the address
66+
// will be read from this parameter.
67+
//
68+
// ViewSizeInOut - The size of the view in bytes. This pointer will be accessed to store the
69+
// size of the view after its creation.
70+
//
71+
// AllocationType - The type of allocation. MEM_TOP_DOWN and MEM_SHARED are the allowed flags.
72+
//
73+
// SectionOffset - The offset within the file or section. If this isn't aligned to a page boundary,
74+
// then neither will the output base address.
75+
//
76+
// Protection - The protection applied to the pages to be committed. See OSAllocateVirtualMemory for
77+
// more information.
78+
//
79+
BSTATUS MmMapViewOfObject(
80+
HANDLE MappedObject,
81+
void** BaseAddressOut,
82+
size_t* ViewSizeInOut,
83+
int AllocationType,
84+
uint64_t SectionOffset,
85+
int Protection
86+
)
87+
{
88+
if (Protection & ~(PAGE_READ | PAGE_WRITE | PAGE_EXECUTE))
89+
return STATUS_INVALID_PARAMETER;
90+
91+
if (AllocationType & ~(MEM_COMMIT | MEM_SHARED | MEM_TOP_DOWN))
92+
return STATUS_INVALID_PARAMETER;
93+
94+
if (!ViewSizeInOut)
95+
return STATUS_INVALID_PARAMETER;
96+
97+
BSTATUS Status;
98+
PFILE_OBJECT FileObject = NULL;
99+
//PMMSECTION SectionObject = NULL;
100+
101+
Status = ObReferenceObjectByHandle(MappedObject, IoFileType, (void**) &FileObject);
102+
if (SUCCEEDED(Status))
103+
{
104+
Status = MmMapViewOfFile(
105+
FileObject,
106+
BaseAddressOut,
107+
ViewSizeInOut,
108+
AllocationType,
109+
SectionOffset,
110+
Protection
111+
);
112+
113+
ObDereferenceObject(FileObject);
114+
return Status;
115+
}
116+
117+
/*
118+
TODO:
119+
120+
Status = ObReferenceObjectByHandle(MappedObject, MmSectionType, (void**) &FileObject);
121+
if (SUCCEEDED(Status))
122+
{
123+
Status = MmMapViewOfSection(
124+
FileObject,
125+
BaseAddressOut,
126+
ViewSizeInOut,
127+
AllocationType,
128+
SectionOffset,
129+
Protection
130+
);
131+
132+
ObDereferenceObject(FileObject);
133+
return Status;
134+
}
135+
*/
136+
137+
return STATUS_TYPE_MISMATCH;
138+
}

0 commit comments

Comments
 (0)