Skip to content

Commit e593344

Browse files
committed
Add kmalloc and kfree to allocate and free memory when running in kernel mode. Kernel memory is tracked in it's own memory usage structures. This is important because kernel code can run in any context, but memory allocated in one context shouldn't be freed in another, but can be referenced in any context.
1 parent 35683dd commit e593344

File tree

14 files changed

+313
-22
lines changed

14 files changed

+313
-22
lines changed

MyOS_1/Build_Number.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
// Define a build number. This number will be incremented by a simple console program called by a post-build event
44
// It's put here in its own file to keep the other program from messing up the source
55
#define \
6-
BUILD_NUMBER 6507
6+
BUILD_NUMBER 6563

MyOS_1/Drivers/Virtio_Net.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include "../Networking/IPv4.h"
1313
#include "Virtio.h"
1414
#include "../Timers/System_Clock.h"
15+
#include "../Console_Serial.h"
16+
#include "../paging.h"
17+
#include "../Tasks/Context.h"
1518

1619
// TODO: Support multiple NIC's
1720

@@ -301,6 +304,8 @@ void _declspec(naked) VirtIO_Net_InterruptHandler()
301304

302305
bool VirtIO_Net_SharedInterruptHandler(void)
303306
{
307+
_disable();
308+
304309
if (debugLevel)
305310
terminal_writestring(" --------- virtio-net interrupt fired! -------\n");
306311

@@ -470,6 +475,14 @@ void VirtIO_Net_SendPacket(Ethernet_Header *packet, uint16_t dataSize)
470475
return;
471476
}
472477

478+
479+
if (/*(uint32_t)(&transmitQueue.descriptors[descIndex2]) == 0x2800000 || (uint32_t)(&transmitQueue.descriptors[descIndex2].address) == 0x2800000
480+
||*/ (uint32_t)packetBuffer == 0x2800000)
481+
{
482+
//serial_printf("Got em - %s\n", tasks[currentTask].imageName);
483+
//Paging_Print_Page_Table(tasks[currentTask].cr3);
484+
}
485+
473486
memcpy(packetBuffer, packet, dataSize);
474487
// (TODO: malloc returns identity-mapped addresses for now but later we'll need a function to convert virtual to physical)
475488

MyOS_1/Interrupts/Interrupts.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void _declspec(naked) default_interrupt_handler(void)
4747

4848
void _declspec(naked) irq11_shared_interrupt_handler(void)
4949
{
50+
_disable();
5051
_asm pushad;
5152

5253
++interrupts_fired;
@@ -73,6 +74,7 @@ void _declspec(naked) irq11_shared_interrupt_handler(void)
7374

7475
void _declspec(naked) irq9_shared_interrupt_handler(void)
7576
{
77+
_disable();
7678
_asm pushad;
7779

7880
++interrupts_fired;

MyOS_1/MyOS_1.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@
307307
<ClCompile Include="Interrupts\Interrupts.c" />
308308
<ClCompile Include="Interrupts\PIC.c" />
309309
<ClCompile Include="Interrupts\System_Calls.c" />
310+
<ClCompile Include="kmisc.c" />
310311
<ClCompile Include="main.c">
311312
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">UninitializedLocalUsageCheck</BasicRuntimeChecks>
312313
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">UninitializedLocalUsageCheck</BasicRuntimeChecks>
@@ -362,6 +363,7 @@
362363
<ClInclude Include="Interrupts\Interrupts.h" />
363364
<ClInclude Include="Interrupts\PIC.h" />
364365
<ClInclude Include="Interrupts\System_Calls.h" />
366+
<ClInclude Include="kmisc.h" />
365367
<ClInclude Include="misc.h" />
366368
<ClInclude Include="multiboot.h" />
367369
<ClInclude Include="myos_io.h" />

MyOS_1/MyOS_1.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@
222222
<ClCompile Include="Debugging\Debug.c">
223223
<Filter>Source Files\Debugging</Filter>
224224
</ClCompile>
225+
<ClCompile Include="kmisc.c">
226+
<Filter>Source Files</Filter>
227+
</ClCompile>
225228
</ItemGroup>
226229
<ItemGroup>
227230
<ClInclude Include="misc.h">
@@ -374,6 +377,9 @@
374377
<ClInclude Include="Debugging\Debug.h">
375378
<Filter>Header Files\Debugging</Filter>
376379
</ClInclude>
380+
<ClInclude Include="kmisc.h">
381+
<Filter>Header Files</Filter>
382+
</ClInclude>
377383
</ItemGroup>
378384
<ItemGroup>
379385
<Text Include="Referenced_Reading.txt">

MyOS_1/Networking/TFTP.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "Ethernet.h"
55
#include "../Drivers/Virtio_Net.h"
66
#include "../Tasks/Context.h"
7+
#include "../Console_Serial.h"
78

89
// TODO: Support multiple transactions
910
uint16_t transactionID;
@@ -166,6 +167,7 @@ uint16_t TFTP_RequestFile(uint32_t serverIP, const char *filename, const char *t
166167
// TODO: Seems like Qemu and VirtualBox don't support writing files via TFTP so I can't finish this :(
167168
uint16_t TFTP_WriteFile(uint32_t serverIP, const char *filename, const char *transferMode, uint8_t *sourceMAC)
168169
{
170+
return 1235; // Don't even bother
169171
TFTP_RequestHeader *tftpData;
170172
size_t filenameLength = strlen(filename) + 1; // length of filename plus null terminator
171173
size_t transferModeLength = strlen(transferMode) + 1;
@@ -285,6 +287,7 @@ void TFTP_ProcessDataPacket(TFTP_DataHeader *dataPacket, uint16_t sourcePort, ui
285287
}
286288
else
287289
{
290+
//serial_printf("tftpTaskIndex: %d, currentTask: %d\n", tftpTaskIndex, currentTask);
288291
// We need to swap out the page directory with the one for the task that requested the file
289292
__writecr3(tasks[tftpTaskIndex].cr3);
290293

MyOS_1/kmisc.c

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#include "paging.h"
2+
#include "printf.h"
3+
#include "kmisc.h"
4+
#include "misc.h"
5+
6+
// Functions used by the kernel & drivers
7+
8+
// TODO: This might all go out the window in favor of conditionally-compiling misc.c functions; I haven't decided yet.
9+
10+
extern uint32_t memoryNextAvailableAddress;
11+
extern uint32_t pagedMemoryAvailable;
12+
13+
// TODO: Change this to a more robust scheme (?)
14+
ALLOCATION_ARRAY kallocationArray = { 0 };
15+
unsigned int knextAllocationSlot = 0;
16+
17+
// Very, very basic support for freeing memory:
18+
ALLOCATION_ARRAY kfreeMemoryArray = { 0 };
19+
unsigned int knextFreeMemorySlot = 0;
20+
21+
#ifdef DEBUG_MEM
22+
#define noFileName "FILENAME NOT SET";
23+
char *dbgMemFilename = noFileName;
24+
int dbgMemLineNumber = 0;
25+
char *dbgFreeFilename = noFileName;
26+
int dbgFreeLineNumber = 0;
27+
#endif
28+
29+
inline void addAllocationToKFreeMemoryArray(int allocationIndex)
30+
{
31+
// Try to add this memory to the free memory array
32+
if (knextFreeMemorySlot == MAX_ALLOCATIONS)
33+
{
34+
kprintf("NSLFM");
35+
return;
36+
}
37+
38+
kfreeMemoryArray.address[knextFreeMemorySlot] = kallocationArray.address[allocationIndex];
39+
kfreeMemoryArray.size[knextFreeMemorySlot] = kallocationArray.size[allocationIndex];
40+
kfreeMemoryArray.inUse[knextFreeMemorySlot++] = true;
41+
}
42+
43+
// Allocate some kernel memory. Mostly this is meant to be used by drivers.
44+
// This will be mapped into every tasks page space and will be allocated contiguously
45+
// TODO: Is it better to have this crazy scheme with the two functions, or just modify malloc to make sure
46+
// it never reuses user-space memory when called from the kernel?
47+
48+
void* kmalloc(size_t size)
49+
{
50+
if (knextAllocationSlot >= MAX_ALLOCATIONS)
51+
{
52+
kprintf("Maximum memory allocations exceeded!\n");
53+
return NULL;
54+
}
55+
56+
#ifdef DEBUG_MEM
57+
kallocationArray.lineNumber[knextAllocationSlot] = dbgMemLineNumber;
58+
strncpy(kallocationArray.filename[knextAllocationSlot], dbgMemFilename, MAX_DEBUG_FILENAME_LENGTH);
59+
dbgMemFilename = noFileName;
60+
dbgMemLineNumber = 0;
61+
#endif
62+
63+
// See if there's freed memory available to reallocate (first fit algorithm; memory will end up wasted)
64+
for (size_t i = 0; i < knextFreeMemorySlot; ++i)
65+
{
66+
if (kfreeMemoryArray.size[i] >= size)
67+
{
68+
// We found a piece of free memory we can reuse
69+
70+
// Keep track of the memory in our allocations array
71+
kallocationArray.address[knextAllocationSlot] = kfreeMemoryArray.address[i];
72+
kallocationArray.size[knextAllocationSlot] = kfreeMemoryArray.size[i];
73+
kallocationArray.inUse[knextAllocationSlot] = true;
74+
75+
// We want to keep kfreeMemoryArray from fragmenting, so we'll copy
76+
// last used free memory entry of the array to the i position and decrease
77+
// the used portion of the array by one
78+
--knextFreeMemorySlot;
79+
if (knextFreeMemorySlot)
80+
{
81+
kfreeMemoryArray.address[i] = kfreeMemoryArray.address[knextFreeMemorySlot];
82+
kfreeMemoryArray.size[i] = kfreeMemoryArray.size[knextFreeMemorySlot];
83+
}
84+
// The last entry is no longer in use
85+
kfreeMemoryArray.inUse[knextFreeMemorySlot] = false;
86+
87+
#ifdef DEBUG_MEM
88+
//printf("Reusing freed memory from slot %d, (reuse #%d)\n", i, ++reuses);
89+
#endif
90+
return (void *)kallocationArray.address[knextAllocationSlot++];
91+
}
92+
}
93+
94+
uint32_t availableAddress = memoryNextAvailableAddress;
95+
96+
#ifdef DEBUG_MEM
97+
printf("Allocating new %d bytes\n", size);
98+
#endif
99+
100+
//if(debugLevel)
101+
//printf("size: %d\nadrress: %d\n", size, memoryNextAvailableAddress);
102+
103+
/*terminal_writestring("Paged memory available: ");
104+
terminal_print_int(pagedMemoryAvailable);
105+
terminal_newline();*/
106+
107+
// see if we need to allocate a page
108+
if (size > pagedMemoryAvailable)
109+
{
110+
// TODO: Support dynamic page granularity, not just large pages
111+
unsigned int pagesToAllocate = size / FOUR_MEGABYTES;
112+
113+
// check for remainder from division
114+
if (pagesToAllocate * FOUR_MEGABYTES < size)
115+
++pagesToAllocate;
116+
117+
// Allocate the pages
118+
unsigned int pagesAllocated;
119+
KPageAllocator(pagesToAllocate, &pagesAllocated, &availableAddress);
120+
121+
// We need to ensure the pages are in order
122+
if (!availableAddress || (pagesAllocated < pagesToAllocate))
123+
{
124+
kprintf("Returning NULL, %d pages allocated out of %d\n", pagesAllocated, pagesToAllocate);
125+
// TODO: Free allocated pages
126+
return NULL;
127+
}
128+
129+
// TODO: see if the page we allocated follows the previous page
130+
// for now, we'll just ignore the old allocated memory
131+
pagedMemoryAvailable = pagesAllocated * FOUR_MEGABYTES;
132+
133+
memoryNextAvailableAddress = availableAddress;
134+
}
135+
136+
pagedMemoryAvailable -= size;
137+
availableAddress = memoryNextAvailableAddress;
138+
memoryNextAvailableAddress += size;
139+
140+
// Keep track of the memory in our allocations array
141+
kallocationArray.address[knextAllocationSlot] = availableAddress;
142+
kallocationArray.size[knextAllocationSlot] = size;
143+
kallocationArray.inUse[knextAllocationSlot++] = true;
144+
145+
return (void *)availableAddress;
146+
}
147+
148+
void kfree(void *ptr)
149+
{
150+
// Find this pointer in the allocation array
151+
for (size_t i = 0; i < knextAllocationSlot; ++i)
152+
{
153+
if (kallocationArray.address[i] == (uint32_t)ptr)
154+
{
155+
if (kallocationArray.inUse[i])
156+
{
157+
addAllocationToKFreeMemoryArray(i);
158+
159+
// We want to keep the allocation array from being fragmented, so we
160+
// copy the final entry in allocation array to the i position and
161+
// decrease the size of the allocation array
162+
--knextAllocationSlot;
163+
if (knextAllocationSlot)
164+
{
165+
kallocationArray.address[i] = kallocationArray.address[knextAllocationSlot];
166+
kallocationArray.size[i] = kallocationArray.size[knextAllocationSlot];
167+
}
168+
169+
kallocationArray.inUse[knextAllocationSlot] = false;
170+
}
171+
else
172+
{
173+
kprintf("free() called to free already-freed pointer, 0x%lX\n", ptr);
174+
}
175+
176+
return;
177+
}
178+
}
179+
180+
kprintf("free() called with invalid pointer: 0x%lX", ptr);
181+
#ifdef DEBUG_MEM
182+
printf(" from %s, line %d\n", dbgFreeFilename, dbgFreeLineNumber);
183+
dbgFreeFilename = noFileName;
184+
dbgFreeLineNumber = 0;
185+
//for (;;)
186+
// __halt();
187+
#else
188+
kprintf("\n");
189+
#endif
190+
}

MyOS_1/kmisc.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif /* __cplusplus */
6+
7+
#include <stdint.h>
8+
9+
void* kmalloc(size_t size);
10+
void kfree(void *ptr);
11+
12+
#ifdef __cplusplus
13+
};
14+
#endif /* __cplusplus */

MyOS_1/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ void KeStartupPhase2(multiboot_info *multibootInfo)
133133
//Mouse_Init();
134134

135135
// Execute autoexec.bat (if it exists)
136-
//Autoexec();
136+
Autoexec();
137137

138138
// Say Hello
139139
terminal_writestring("Hello world!\n");

0 commit comments

Comments
 (0)