1
// Inferno utils/8a/l.s
2
// http://code.google.com/p/inferno-os/source/browse/utils/8a/l.s
4
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6
// Portions Copyright © 1997-1999 Vita Nuova Limited
7
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8
// Portions Copyright © 2004,2006 Bruce Ellis
9
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11
// Portions Copyright © 2009 The Go Authors. All rights reserved.
13
// Permission is hereby granted, free of charge, to any person obtaining a copy
14
// of this software and associated documentation files (the "Software"), to deal
15
// in the Software without restriction, including without limitation the rights
16
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
// copies of the Software, and to permit persons to whom the Software is
18
// furnished to do so, subject to the following conditions:
20
// The above copyright notice and this permission notice shall be included in
21
// all copies or substantial portions of the Software.
23
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
32
* Memory and machine-specific definitions. Used in C and assembler.
38
#define BI2BY 8 /* bits per byte */
39
#define BI2WD 32 /* bits per word */
40
#define BY2WD 4 /* bytes per word */
41
#define BY2PG 4096 /* bytes per page */
42
#define WD2PG (BY2PG/BY2WD) /* words per page */
43
#define PGSHIFT 12 /* log(BY2PG) */
44
#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
46
#define MAXMACH 1 /* max # cpus system can run */
51
#define HZ (20) /* clock frequency */
52
#define MS2HZ (1000/HZ) /* millisec per clock tick */
53
#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
54
#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
55
#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
58
* Fundamental addresses
65
* Kernel is at 2GB-4GB
67
* To avoid an extra page map, both the user stack (USTKTOP) and
68
* the temporary user stack (TSTKTOP) should be in the the same
71
#define UZERO 0 /* base of user address space */
72
#define UTZERO (UZERO+BY2PG) /* first address in user text */
73
#define KZERO 0x80000000 /* base of kernel address space */
74
#define KTZERO KZERO /* first address in kernel text */
75
#define USERADDR 0xC0000000 /* struct User */
76
#define UREGADDR (USERADDR+BY2PG-4*19)
77
#define TSTKTOP USERADDR /* end of new stack in sysexec */
79
#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
80
#define USTKSIZE (16*1024*1024 - TSTKSIZ*BY2PG) /* size of user stack */
81
#define ROMBIOS (KZERO|0xF0000)
85
#define isphys(x) (((ulong)x)&KZERO)
88
* known 80386 segments (in GDT) and their selectors
90
#define NULLSEG 0 /* null segment */
91
#define KDSEG 1 /* kernel data/stack */
92
#define KESEG 2 /* kernel executable */
93
#define UDSEG 3 /* user data/stack */
94
#define UESEG 4 /* user executable */
95
#define TSSSEG 5 /* task segment */
97
#define SELGDT (0<<3) /* selector is in gdt */
98
#define SELLDT (1<<3) /* selector is in ldt */
100
#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
102
#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
103
#define KESEL SELECTOR(KESEG, SELGDT, 0)
104
#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
105
#define UESEL SELECTOR(UESEG, SELGDT, 3)
106
#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
107
#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
110
* fields in segment descriptors
112
#define SEGDATA (0x10<<8) /* data/stack segment */
113
#define SEGEXEC (0x18<<8) /* executable segment */
114
#define SEGTSS (0x9<<8) /* TSS segment */
115
#define SEGCG (0x0C<<8) /* call gate */
116
#define SEGIG (0x0E<<8) /* interrupt gate */
117
#define SEGTG (0x0F<<8) /* task gate */
118
#define SEGTYPE (0x1F<<8)
120
#define SEGP (1<<15) /* segment present */
121
#define SEGPL(x) ((x)<<13) /* priority level */
122
#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
123
#define SEGG (1<<23) /* granularity 1==4k (for other) */
124
#define SEGE (1<<10) /* expand down */
125
#define SEGW (1<<9) /* writable (for data/stack) */
126
#define SEGR (1<<9) /* readable (for code) */
127
#define SEGD (1<<22) /* default 1==32bit (for code) */
132
#define PTEMAPMEM (1024*1024) /* ??? */
133
#define SEGMAPSIZE 16 /* ??? */
134
#define PTEPERTAB (PTEMAPMEM/BY2PG) /* ??? */
135
#define PPN(x) ((x)&~(BY2PG-1))
140
#define PTEVALID (1<<0)
141
#define PTEUNCACHED 0 /* everything is uncached */
142
#define PTEWRITE (1<<1)
143
#define PTERONLY (0<<1)
144
#define PTEKERNEL (0<<2)
145
#define PTEUSER (1<<2)
148
* flag register bits that we care about
152
#define OP16 BYTE $0x66
155
* about to walk all over ms/dos - turn off interrupts
163
* This part of l.s is used only in the boot kernel.
164
* It assumes that we are in real address mode, i.e.,
165
* that we look like an 8086.
168
* relocate everything to a half meg and jump there
169
* - looks wierd because it is being assembled by a 32 bit
170
* assembler for a 16 bit world
180
/* JMPFAR 0X8000:$lowcore(SB) /**/
188
* now that we're in low core, update the DS
194
* goto protected mode
196
/* MOVL tgdtptr(SB),GDTR /**/
206
* clear prefetch queue (wierd code to avoid optimizations)
216
/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/
219
WORD $SELECTOR(1, SELGDT, 0)
226
/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/
229
LONG $mode32bit-KZERO(SB)
230
WORD $SELECTOR(2, SELGDT, 0)
232
TEXT mode32bit(SB),$0
239
LEAL edata-KZERO(SB),SI
244
LEAL end-KZERO(SB),CX
250
* make a bottom level page table page that maps the first
251
* 16 meg of physical memory
253
LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */
254
ADDL $(BY2PG-1),AX /* must be page aligned */
255
ANDL $(~(BY2PG-1)),AX /* ... */
256
MOVL $(4*1024),CX /* pte's per page */
257
MOVL $((((4*1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
260
SUBL $(1<<PGSHIFT),BX
264
* make a top level page table page that maps the first
265
* 16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg
269
ADDL $(PTEVALID|PTEKERNEL|PTEWRITE),BX
271
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX)
274
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX)
277
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX)
280
MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX)
283
* point processor to top level page & turn on paging
288
ANDL $~(0x8|0x2),AX /* TS=0, MP=0 */
292
* use a jump to an absolute location to get the PC into
306
ADDL $(MACHSIZE-4),SP /* start stack under machine struct */
321
GLOBL mach0+0(SB), $MACHSIZE
324
GLOBL tpt(SB), $(BY2PG*6)
327
* gdt to get us to 32-bit/segmented/unpaged mode
331
/* null descriptor */
335
/* data segment descriptor for 4 gigabytes (PL 0) */
337
LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
339
/* exec segment descriptor for 4 gigabytes (PL 0) */
341
LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
344
* pointer to initial gdt
372
* input a string of shorts from a port
382
* output a string of shorts to a port
388
CLD; REP; OP16; OUTSL
401
* routines to load/read various system registers
404
TEXT putidt(SB),$0 /* interrupt descriptor table */
413
TEXT putgdt(SB),$0 /* global descriptor table */
421
TEXT putcr3(SB),$0 /* top level page table pointer */
426
TEXT puttr(SB),$0 /* task register */
431
TEXT getcr0(SB),$0 /* coprocessor bits */
435
TEXT getcr2(SB),$0 /* fault address */
442
ORL $0x4,AX /* EM=1 */;\
447
ANDL $~0x4,AX /* EM=0 */;\
450
TEXT fpoff(SB),$0 /* turn off floating point */
454
TEXT fpinit(SB),$0 /* turn on & init the floating point */
459
FLDCW 0(SP) /* ignore underflow/precision, signal others */
464
TEXT fpsave(SB),$0 /* save floating point state and turn off */
471
TEXT fprestore(SB),$0 /* turn on floating point and restore regs */
478
TEXT fpstatus(SB),$0 /* get floating point status */
638
ADDL $8,SP /* error code and trap type */
659
ADDL $8,SP /* error code and trap type */
663
* interrupt level is interrupts on or off
684
* do nothing whatsoever till interrupt happens
691
* label consists of a stack pointer and a PC
693
TEXT gotolabel(SB),$0
695
MOVL 0(AX),SP /* restore sp */
696
MOVL 4(AX),AX /* put return pc on the stack */
698
MOVL $1,AX /* return 1 */
703
MOVL SP,0(AX) /* store sp */
704
MOVL 0(SP),BX /* store return pc */
706
MOVL $0,AX /* return 0 */
710
* Used to get to the first process.
711
* Set up an interrupt return frame and IRET to user level.
714
PUSHL $(UDSEL) /* old ss */
715
PUSHL $(USTKTOP) /* old sp */
716
PUSHFL /* old flags */
717
PUSHL $(UESEL) /* old cs */
718
PUSHL $(UTZERO+32) /* old pc */
727
* set configuration register