forked from johnjones4/DinoDOS
-
Notifications
You must be signed in to change notification settings - Fork 1
/
kernel.asm
295 lines (254 loc) · 6.73 KB
/
kernel.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
;kernel.asm
;Michael Black, 2007
;kernel.asm contains assembly functions that you can use in your kernel
.global _putInMemory
.global _interrupt
.global _makeInterrupt21
.global _launchProgram
.extern _handleInterrupt21
.global _makeTimerInterrupt
.extern _handleTimerInterrupt
.global _returnFromTimer
.global _initializeProgram
.global _setKernelDataSegment
.global _restoreDataSegment
.global _resetSegments
;void putInMemory (int segment, int address, char character)
_putInMemory:
push bp
mov bp,sp
push ds
mov ax,[bp+4]
mov si,[bp+6]
mov cl,[bp+8]
mov ds,ax
mov [si],cl
pop ds
pop bp
ret
;int interrupt (int number, int AX, int BX, int CX, int DX)
_interrupt:
push bp
mov bp,sp
mov ax,[bp+4] ;get the interrupt number in AL
push ds ;use self-modifying code to call the right interrupt
mov bx,cs
mov ds,bx
mov si,#intr
mov [si+1],al ;change the 00 below to the contents of AL
pop ds
mov ax,[bp+6] ;get the other parameters AX, BX, CX, and DX
mov bx,[bp+8]
mov cx,[bp+10]
mov dx,[bp+12]
intr: int #0x00 ;call the interrupt (00 will be changed above)
;GWB - Allow all of AX to be returned so that we can return
; negative numbers on errors.
;mov ah,#0 ;we only want AL returned
pop bp
ret
;void makeInterrupt21()
;this sets up the interrupt 0x21 vector
;when an interrupt 0x21 is called in the future,
;_interrupt21ServiceRoutine will run
_makeInterrupt21:
;get the address of the service routine
mov dx,#_interrupt21ServiceRoutine
push ds
mov ax, #0 ;interrupts are in lowest memory
mov ds,ax
mov si,#0x84 ;interrupt 0x21 vector (21 * 4 = 84)
mov ax,cs ;have interrupt go to the current segment
mov [si+2],ax
mov [si],dx ;set up our vector
pop ds
ret
;this is called when interrupt 21 happens
;it will call your function:
;void handleInterrupt21 (int AX, int BX, int CX, int DX)
_interrupt21ServiceRoutine:
push dx
push cx
push bx
push ax
sti
call _handleInterrupt21
;GWB: Modification here to allow handleInterrupt21 to
; return an int value via the ax register.
;pop ax
pop bx ; pop pushed ax to discard and leave rv in ax.
pop bx
pop cx
pop dx
iret
;this is called to start a program that is loaded into memory
;void launchProgram(int segment)
_launchProgram:
mov bp,sp
mov bx,[bp+2] ;get the segment into bx
mov ax,cs ;modify the jmp below to jump to our segment
mov ds,ax ;this is self-modifying code
mov si,#jump
mov [si+3],bx ;change the first 0000 to the segment
mov ds,bx ;set up the segment registers
mov ss,bx
mov es,bx
mov sp,#0xfff0 ;set up the stack pointer
mov bp,#0xfff0
sti
jump: jmp #0x0000:0x0000 ;and start running (the first 0000 is changed above)
;void makeTimerInterrupt()
;sets up the timer's interrupt service routine
_makeTimerInterrupt:
cli
mov dx,#timer_ISR ;get address of timerISR in dx
push ds
mov ax,#0 ;interrupts are at lowest memory
mov ds,ax
mov si,#0x20 ;timer interrupt vector (8 * 4)
mov ax,cs ;have interrupt go to the current segment
mov [si+2],ax
mov [si],dx ;address of our vector
pop ds
;start the timer
mov al,#0x36 ; 0011 0110
out #0x43,al
mov ax,#0xFF ; 0xFFFF as count (~12x / second)
out #0x40,al
mov ax,#0xFF
out #0x40,al
sti
ret
;this routine runs on timer interrupts
timer_ISR:
;disable interrupts
cli
;save all regs for the old process on the old process's stack
push bx
push cx
push dx
push si
push di
push bp
push ax
push ds
push es
;reset interrupt controller so it performs more interrupts
mov al,#0x20
out #0x20,al
;get the segment (ss) and the stack pointer (sp) - we need to keep these
mov bx,ss
mov cx,sp
;set all segments to the kernel
mov ax,#0x1000
mov ds,ax
mov es,ax
mov ss,ax
;set the kernel's stack
mov ax,#0xdff0
mov sp,ax
mov bp,ax
;call handle interrupt with 2 parameters: the segment, the stack pointer.
mov ax,#0
push cx
push bx
call _handleTimerInterrupt
;void returnFromTimer(int segment, int sp)
;returns from a timer interrupt to a different process
_returnFromTimer:
;pop off the local return address - don't need it
pop ax
;get the segment and stack pointer
pop bx
pop cx
;get rid of the junk from the two calls and no returns
pop ax
pop ax
pop ax
pop ax
pop ax
pop ax
pop ax
;set up the stack
mov sp,cx
;set up the stack segment
mov ss,bx
;now we're back to the program's area
;reload the registers (if this is it's first time running, these will be zeros)
pop es
pop ds
pop ax
pop bp
pop di
pop si
pop dx
pop cx
pop bx
;enable interrupts and return
sti
iret
;void initializeProgram(int segment)
;this initializes a new program but doesn't start it running
;the scheduler will take care of that
;the program will be located at the beginning of the segment at [sp+2]
_initializeProgram:
;bx=new segment
push bp
mov bp,sp
mov bx,[bp+4]
;make a stack image so that the timer interrupt can start this program
;save the caller's stack pointer and segment
mov cx,sp
mov dx,ss
mov ax,#0xff18 ;this allows an initial sp of 0xff00
mov sp,ax
mov ss,bx
mov ax,#0 ;IP
push ax
mov ax,bx ;CS
push ax
mov ax,#0x0 ;a normal flag setting
push ax
mov ax,#0 ;set all the general registers to 0
push ax ;bx
push ax ;cx
push ax ;dx
push ax ;si
push ax ;di
push ax ;bp
push ax ;ax
mov ax,bx
push ax ;ds
push ax ;es
;restore the stack to the caller
mov sp,cx
mov ss,dx
pop bp
ret
;void setKernelDataSegment()
;sets the data segment to the kernel, saving the current ds on the stack
_setKernelDataSegment:
pop bx
push ds
push bx
mov ax,#0x1000
mov ds,ax
ret
;void restoreDataSegment()
;restores the data segment
_restoreDataSegment:
pop bx
pop ds
push bx
ret
;void resetSegments()
;resets the data, stack and execution segments
;to the kernel segment at 0x1000
_resetSegments:
pop bx
mov ax,#0x1000
mov ds,ax
mov ss,ax
mov es,ax
push bx
ret