diff options
author | 2025-01-23 10:41:10 +0800 | |
---|---|---|
committer | 2025-01-23 10:41:10 +0800 | |
commit | e6f77b7ea3e38c9853bee60b275f3f89d252a5b3 (patch) | |
tree | 80bfbabed9d4cbcf9fa62677f78b34279d7e2f87 | |
download | linux-0.11-e6f77b7ea3e38c9853bee60b275f3f89d252a5b3.tar.gz linux-0.11-e6f77b7ea3e38c9853bee60b275f3f89d252a5b3.zip |
120 files changed, 14987 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..951e3c4 --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1,17 @@ | |||
1 | .*.sw* | ||
2 | .vscode/* | ||
3 | compile_commands.json | ||
4 | .cache/* | ||
5 | |||
6 | # Ignore all the make output | ||
7 | *.o | ||
8 | bootsect | ||
9 | setup | ||
10 | Image | ||
11 | blk_drv.a | ||
12 | chr_drv.a | ||
13 | keyboard.s | ||
14 | math.a | ||
15 | lib.a | ||
16 | System.map | ||
17 | system | ||
diff --git a/bochs/linux-0.11-gui.bxrc b/bochs/linux-0.11-gui.bxrc new file mode 100644 index 0000000..31dc1dd --- /dev/null +++ b/bochs/linux-0.11-gui.bxrc | |||
@@ -0,0 +1,11 @@ | |||
1 | romimage: file=$BXSHARE/BIOS-bochs-latest | ||
2 | megs: 16 | ||
3 | vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest | ||
4 | |||
5 | floppya: 1_44="$OSLAB_PATH/src/Image", status=inserted | ||
6 | ata0-master: type=disk, path="$OSLAB_PATH/hdc-0.11.img", mode=flat, cylinders=204, heads=16, spt=38 | ||
7 | boot: a | ||
8 | log: $OSLAB_PATH/bochsout.txt | ||
9 | |||
10 | display_library: x, options="gui_debug" | ||
11 | |||
diff --git a/bochs/linux-0.11.bxrc b/bochs/linux-0.11.bxrc new file mode 100644 index 0000000..1903f1d --- /dev/null +++ b/bochs/linux-0.11.bxrc | |||
@@ -0,0 +1,12 @@ | |||
1 | romimage: file=$BXSHARE/BIOS-bochs-latest | ||
2 | megs: 16 | ||
3 | vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest | ||
4 | |||
5 | floppya: 1_44="$OSLAB_PATH/src/Image", status=inserted | ||
6 | ata0-master: type=disk, path="$OSLAB_PATH/hdc-0.11.img", mode=flat, cylinders=204, heads=16, spt=38 | ||
7 | boot: a | ||
8 | log: $OSLAB_PATH/bochsout.txt | ||
9 | |||
10 | display_library: x | ||
11 | #display_library: sdl | ||
12 | |||
diff --git a/bochsout.txt b/bochsout.txt new file mode 100644 index 0000000..e4bbdb7 --- /dev/null +++ b/bochsout.txt | |||
@@ -0,0 +1,316 @@ | |||
1 | 00000000000i[ ] Bochs x86 Emulator 2.8 | ||
2 | 00000000000i[ ] Built from GitHub snapshot on March 10, 2024 | ||
3 | 00000000000i[ ] Timestamp: Sun Mar 10 08:00:00 CET 2024 | ||
4 | 00000000000i[ ] System configuration | ||
5 | 00000000000i[ ] processors: 1 (cores=1, HT threads=1) | ||
6 | 00000000000i[ ] A20 line support: yes | ||
7 | 00000000000i[ ] IPS is set to 4000000 | ||
8 | 00000000000i[ ] CPU configuration | ||
9 | 00000000000i[ ] SMP support: no | ||
10 | 00000000000i[ ] level: 6 | ||
11 | 00000000000i[ ] APIC support: xapic | ||
12 | 00000000000i[ ] FPU support: yes | ||
13 | 00000000000i[ ] MMX support: yes | ||
14 | 00000000000i[ ] 3dnow! support: no | ||
15 | 00000000000i[ ] SEP support: yes | ||
16 | 00000000000i[ ] SIMD support: sse2 | ||
17 | 00000000000i[ ] XSAVE support: no | ||
18 | 00000000000i[ ] AES support: no | ||
19 | 00000000000i[ ] SHA support: no | ||
20 | 00000000000i[ ] MOVBE support: no | ||
21 | 00000000000i[ ] ADX support: no | ||
22 | 00000000000i[ ] x86-64 support: no | ||
23 | 00000000000i[ ] MWAIT support: yes | ||
24 | 00000000000i[ ] Optimization configuration | ||
25 | 00000000000i[ ] RepeatSpeedups support: no | ||
26 | 00000000000i[ ] Fast function calls: no | ||
27 | 00000000000i[ ] Handlers Chaining speedups: no | ||
28 | 00000000000i[ ] Devices configuration | ||
29 | 00000000000i[ ] PCI support: i440FX i430FX i440BX | ||
30 | 00000000000i[ ] Networking: no | ||
31 | 00000000000i[ ] Sound support: no | ||
32 | 00000000000i[ ] USB support: no | ||
33 | 00000000000i[ ] VGA extension support: vbe | ||
34 | 00000000000i[IMG ] Disk image modules | ||
35 | 00000000000i[IMG ] flat concat sparse dll growing undoable volatile vmware3 | ||
36 | 00000000000i[IMG ] vmware4 vbox vpc vvfat | ||
37 | 00000000000i[MEM0 ] allocated memory at 0x742f5c1dd010. after alignment, vector=0x742f5c1de000, block_size = 128K | ||
38 | 00000000000i[MEM0 ] 16.00MB | ||
39 | 00000000000i[MEM0 ] mem block size = 0x00020000, blocks=128 | ||
40 | 00000000000i[MEM0 ] rom at 0xfffe0000/131072 ('/usr/local/share/bochs/BIOS-bochs-latest') | ||
41 | 00000000000i[DEV ] will paste characters every 100 iodev timer ticks | ||
42 | 00000000000i[PLUGIN] init_dev of 'pci' plugin device by virtual method | ||
43 | 00000000000i[DEV ] i440FX PMC present at device 0, function 0 | ||
44 | 00000000000i[PLUGIN] init_dev of 'pci2isa' plugin device by virtual method | ||
45 | 00000000000i[DEV ] PIIX3 PCI-to-ISA bridge present at device 1, function 0 | ||
46 | 00000000000i[PLUGIN] init_dev of 'cmos' plugin device by virtual method | ||
47 | 00000000000i[CMOS ] Using local time for initial clock | ||
48 | 00000000000i[CMOS ] Setting initial clock to: Mon Apr 8 22:23:15 2024 tz=utc (time0=1712614995) | ||
49 | 00000000000i[PLUGIN] init_dev of 'dma' plugin device by virtual method | ||
50 | 00000000000i[DMA ] channel 4 used by cascade | ||
51 | 00000000000i[PLUGIN] init_dev of 'pic' plugin device by virtual method | ||
52 | 00000000000i[PLUGIN] init_dev of 'pit' plugin device by virtual method | ||
53 | 00000000000i[PLUGIN] init_dev of 'vga' plugin device by virtual method | ||
54 | 00000000000i[MEM0 ] Register memory access handlers: 0x0000000a0000 - 0x0000000bffff | ||
55 | 00000000000i[VGA ] interval=100000, mode=realtime | ||
56 | 00000000000i[VGA ] Setting VGA update interval to 100000 (10.0 Hz) | ||
57 | 00000000000i[VGA ] VSYNC using standard mode | ||
58 | 00000000000i[MEM0 ] Register memory access handlers: 0x0000e0000000 - 0x0000e0ffffff | ||
59 | 00000000000i[BXVGA ] VBE Bochs Display Extension Enabled | ||
60 | 00000000000i[XGUI ] test_alloc_colors: 16 colors available out of 16 colors tried | ||
61 | 00000000000i[XGUI ] font 8 wide x 16 high, display depth = 24 | ||
62 | 00000000000i[XGUI ] maximum host resolution: x=1920 y=1030 | ||
63 | 00000000000i[MEM0 ] rom at 0xc0000/36352 ('/usr/local/share/bochs/VGABIOS-lgpl-latest') | ||
64 | 00000000000i[PLUGIN] init_dev of 'floppy' plugin device by virtual method | ||
65 | 00000000000i[DMA ] channel 2 used by Floppy Drive | ||
66 | 00000000000i[FLOPPY] fd0: './src/Image' ro=0, h=2,t=80,spt=18 | ||
67 | 00000000000i[FLOPPY] Using boot sequence floppy, none, none | ||
68 | 00000000000i[FLOPPY] Floppy boot signature check is enabled | ||
69 | 00000000000i[PLUGIN] init_dev of 'acpi' plugin device by virtual method | ||
70 | 00000000000i[DEV ] ACPI Controller present at device 1, function 3 | ||
71 | 00000000000i[PLUGIN] init_dev of 'hpet' plugin device by virtual method | ||
72 | 00000000000i[HPET ] initializing HPET | ||
73 | 00000000000i[MEM0 ] Register memory access handlers: 0x0000fed00000 - 0x0000fed003ff | ||
74 | 00000000000i[PLUGIN] init_dev of 'ioapic' plugin device by virtual method | ||
75 | 00000000000i[IOAPIC] initializing I/O APIC | ||
76 | 00000000000i[MEM0 ] Register memory access handlers: 0x0000fec00000 - 0x0000fec00fff | ||
77 | 00000000000i[IOAPIC] IOAPIC enabled (base address = 0xfec00000) | ||
78 | 00000000000i[PLUGIN] init_dev of 'keyboard' plugin device by virtual method | ||
79 | 00000000000i[PLUGIN] init_dev of 'harddrv' plugin device by virtual method | ||
80 | 00000000000i[HD ] HD on ata0-0: './hdc-0.11.img', 'flat' mode | ||
81 | 00000000000i[IMG ] hd_size: 63504384 | ||
82 | 00000000000i[HD ] ata0-0: using specified geometry: CHS=204/16/38 (sector size=512) | ||
83 | 00000000000i[HD ] translation on ata0-0 set to 'none' | ||
84 | 00000000000i[PLUGIN] init_dev of 'pci_ide' plugin device by virtual method | ||
85 | 00000000000i[DEV ] PIIX3 PCI IDE controller present at device 1, function 1 | ||
86 | 00000000000i[PLUGIN] init_dev of 'unmapped' plugin device by virtual method | ||
87 | 00000000000i[PLUGIN] init_dev of 'biosdev' plugin device by virtual method | ||
88 | 00000000000i[PLUGIN] init_dev of 'speaker' plugin device by virtual method | ||
89 | 00000000000e[PCSPK ] Failed to open /dev/console: 权限不够 | ||
90 | 00000000000e[PCSPK ] Deactivating beep on console | ||
91 | 00000000000i[PLUGIN] init_dev of 'extfpuirq' plugin device by virtual method | ||
92 | 00000000000i[PLUGIN] init_dev of 'parallel' plugin device by virtual method | ||
93 | 00000000000i[PAR ] parallel port 1 at 0x0378 irq 7 | ||
94 | 00000000000i[PLUGIN] init_dev of 'serial' plugin device by virtual method | ||
95 | 00000000000i[SER ] com1 at 0x03f8 irq 4 (mode: null) | ||
96 | 00000000000i[PLUGIN] init_dev of 'iodebug' plugin device by virtual method | ||
97 | 00000000000i[PLUGIN] register state of 'pci' plugin device by virtual method | ||
98 | 00000000000i[PLUGIN] register state of 'pci2isa' plugin device by virtual method | ||
99 | 00000000000i[PLUGIN] register state of 'cmos' plugin device by virtual method | ||
100 | 00000000000i[PLUGIN] register state of 'dma' plugin device by virtual method | ||
101 | 00000000000i[PLUGIN] register state of 'pic' plugin device by virtual method | ||
102 | 00000000000i[PLUGIN] register state of 'pit' plugin device by virtual method | ||
103 | 00000000000i[PLUGIN] register state of 'vga' plugin device by virtual method | ||
104 | 00000000000i[PLUGIN] register state of 'floppy' plugin device by virtual method | ||
105 | 00000000000i[PLUGIN] register state of 'unmapped' plugin device by virtual method | ||
106 | 00000000000i[PLUGIN] register state of 'biosdev' plugin device by virtual method | ||
107 | 00000000000i[PLUGIN] register state of 'speaker' plugin device by virtual method | ||
108 | 00000000000i[PLUGIN] register state of 'extfpuirq' plugin device by virtual method | ||
109 | 00000000000i[PLUGIN] register state of 'parallel' plugin device by virtual method | ||
110 | 00000000000i[PLUGIN] register state of 'serial' plugin device by virtual method | ||
111 | 00000000000i[PLUGIN] register state of 'iodebug' plugin device by virtual method | ||
112 | 00000000000i[PLUGIN] register state of 'acpi' plugin device by virtual method | ||
113 | 00000000000i[PLUGIN] register state of 'hpet' plugin device by virtual method | ||
114 | 00000000000i[PLUGIN] register state of 'ioapic' plugin device by virtual method | ||
115 | 00000000000i[PLUGIN] register state of 'keyboard' plugin device by virtual method | ||
116 | 00000000000i[PLUGIN] register state of 'harddrv' plugin device by virtual method | ||
117 | 00000000000i[PLUGIN] register state of 'pci_ide' plugin device by virtual method | ||
118 | 00000000000i[SYS ] bx_pc_system_c::Reset(HARDWARE) called | ||
119 | 00000000000i[CPU0 ] cpu hardware reset | ||
120 | 00000000000i[APIC0 ] allocate APIC id=0 (MMIO enabled) to 0x0000fee00000 | ||
121 | 00000000000i[CPU0 ] CPUID[0x00000000]: 00000005 756e6547 6c65746e 49656e69 | ||
122 | 00000000000i[CPU0 ] CPUID[0x00000001]: 00000633 00010800 00000008 afebfbff | ||
123 | 00000000000i[CPU0 ] CPUID[0x00000002]: 00410601 00000000 00000000 00000000 | ||
124 | 00000000000i[CPU0 ] CPUID[0x00000003]: 00000000 00000000 00000000 00000000 | ||
125 | 00000000000i[CPU0 ] CPUID[0x00000004]: 00000000 00000000 00000000 00000000 | ||
126 | 00000000000i[CPU0 ] CPUID[0x00000005]: 00000040 00000040 00000003 00000020 | ||
127 | 00000000000i[CPU0 ] CPUID[0x80000000]: 80000008 00000000 00000000 00000000 | ||
128 | 00000000000i[CPU0 ] CPUID[0x80000001]: 00000000 00000000 00000000 00000000 | ||
129 | 00000000000i[CPU0 ] CPUID[0x80000002]: 20202020 20202020 20202020 6e492020 | ||
130 | 00000000000i[CPU0 ] CPUID[0x80000003]: 286c6574 50202952 69746e65 52286d75 | ||
131 | 00000000000i[CPU0 ] CPUID[0x80000004]: 20342029 20555043 20202020 00202020 | ||
132 | 00000000000i[CPU0 ] CPUID[0x80000005]: 01ff01ff 01ff01ff 40020140 40020140 | ||
133 | 00000000000i[CPU0 ] CPUID[0x80000006]: 00000000 42004200 02008140 00000000 | ||
134 | 00000000000i[CPU0 ] CPUID[0x80000007]: 00000000 00000000 00000000 00000000 | ||
135 | 00000000000i[CPU0 ] CPUID[0x80000008]: 00002028 00000200 00000000 00000000 | ||
136 | 00000000000i[CPU0 ] CPU Features supported: | ||
137 | 00000000000i[CPU0 ] "x87" | ||
138 | 00000000000i[CPU0 ] "486ni" | ||
139 | 00000000000i[CPU0 ] "pentium_ni" | ||
140 | 00000000000i[CPU0 ] "p6ni" | ||
141 | 00000000000i[CPU0 ] "mmx" | ||
142 | 00000000000i[CPU0 ] "debugext" | ||
143 | 00000000000i[CPU0 ] "vme" | ||
144 | 00000000000i[CPU0 ] "pse" | ||
145 | 00000000000i[CPU0 ] "pae" | ||
146 | 00000000000i[CPU0 ] "pge" | ||
147 | 00000000000i[CPU0 ] "pse36" | ||
148 | 00000000000i[CPU0 ] "mtrr" | ||
149 | 00000000000i[CPU0 ] "pat" | ||
150 | 00000000000i[CPU0 ] "sysenter_sysexit" | ||
151 | 00000000000i[CPU0 ] "clflush" | ||
152 | 00000000000i[CPU0 ] "sse" | ||
153 | 00000000000i[CPU0 ] "sse2" | ||
154 | 00000000000i[CPU0 ] "mwait" | ||
155 | 00000000000i[CPU0 ] "xapic" | ||
156 | 00000000000i[PLUGIN] reset of 'pci' plugin device by virtual method | ||
157 | 00000000000i[PLUGIN] reset of 'pci2isa' plugin device by virtual method | ||
158 | 00000000000i[PLUGIN] reset of 'cmos' plugin device by virtual method | ||
159 | 00000000000i[PLUGIN] reset of 'dma' plugin device by virtual method | ||
160 | 00000000000i[PLUGIN] reset of 'pic' plugin device by virtual method | ||
161 | 00000000000i[PLUGIN] reset of 'pit' plugin device by virtual method | ||
162 | 00000000000i[PLUGIN] reset of 'vga' plugin device by virtual method | ||
163 | 00000000000i[PLUGIN] reset of 'floppy' plugin device by virtual method | ||
164 | 00000000000i[PLUGIN] reset of 'acpi' plugin device by virtual method | ||
165 | 00000000000i[PLUGIN] reset of 'hpet' plugin device by virtual method | ||
166 | 00000000000i[PLUGIN] reset of 'ioapic' plugin device by virtual method | ||
167 | 00000000000i[PLUGIN] reset of 'keyboard' plugin device by virtual method | ||
168 | 00000000000i[PLUGIN] reset of 'harddrv' plugin device by virtual method | ||
169 | 00000000000i[PLUGIN] reset of 'pci_ide' plugin device by virtual method | ||
170 | 00000000000i[PLUGIN] reset of 'unmapped' plugin device by virtual method | ||
171 | 00000000000i[PLUGIN] reset of 'biosdev' plugin device by virtual method | ||
172 | 00000000000i[PLUGIN] reset of 'speaker' plugin device by virtual method | ||
173 | 00000000000i[PLUGIN] reset of 'extfpuirq' plugin device by virtual method | ||
174 | 00000000000i[PLUGIN] reset of 'parallel' plugin device by virtual method | ||
175 | 00000000000i[PLUGIN] reset of 'serial' plugin device by virtual method | ||
176 | 00000000000i[PLUGIN] reset of 'iodebug' plugin device by virtual method | ||
177 | 00000000000i[ ] set SIGINT handler to bx_debug_ctrlc_handler | ||
178 | 00000001740i[BIOS ] BIOS BUILD DATE: 03/10/24 | ||
179 | 00000314450i[KBD ] reset-disable command received | ||
180 | 00000316434i[BIOS ] Starting rombios32 | ||
181 | 00000316872i[BIOS ] Shutdown flag 0 | ||
182 | 00000317471i[BIOS ] ram_size=0x01000000 | ||
183 | 00000317903i[BIOS ] ram_end=16MB | ||
184 | 00000358648i[BIOS ] Found 1 cpu(s) | ||
185 | 00000372586i[BIOS ] bios_table_addr: 0x000fa128 end=0x000fcc00 | ||
186 | 00000700402i[PCI ] i440FX PMC write to PAM register 59 (TLB Flush) | ||
187 | 00001028337i[P2ISA ] PCI IRQ routing: PIRQA# set to 0x0b | ||
188 | 00001028361i[P2ISA ] PCI IRQ routing: PIRQB# set to 0x09 | ||
189 | 00001028385i[P2ISA ] PCI IRQ routing: PIRQC# set to 0x0b | ||
190 | 00001028409i[P2ISA ] PCI IRQ routing: PIRQD# set to 0x09 | ||
191 | 00001028419i[P2ISA ] write: ELCR2 = 0x0a | ||
192 | 00001029188i[BIOS ] PIIX3/PIIX4 init: elcr=00 0a | ||
193 | 00001042810i[BIOS ] PCI: bus=0 devfn=0x00: vendor_id=0x8086 device_id=0x1237 class=0x0600 | ||
194 | 00001045154i[BIOS ] PCI: bus=0 devfn=0x08: vendor_id=0x8086 device_id=0x7000 class=0x0601 | ||
195 | 00001047337i[BIOS ] PCI: bus=0 devfn=0x09: vendor_id=0x8086 device_id=0x7010 class=0x0101 | ||
196 | 00001047572i[PIDE ] BAR #4: i/o base address = 0xc000 | ||
197 | 00001048188i[BIOS ] region 4: 0x0000c000 | ||
198 | 00001050246i[BIOS ] PCI: bus=0 devfn=0x0b: vendor_id=0x8086 device_id=0x7113 class=0x0680 | ||
199 | 00001050522i[ACPI ] new IRQ line = 11 | ||
200 | 00001050536i[ACPI ] new IRQ line = 9 | ||
201 | 00001050564i[ACPI ] new PM base address: 0xb000 | ||
202 | 00001050578i[ACPI ] new SM base address: 0xb100 | ||
203 | 00001050606i[PCI ] setting SMRAM control register to 0x4a | ||
204 | 00001214741i[CPU0 ] Enter to System Management Mode | ||
205 | 00001214752i[CPU0 ] RSM: Resuming from System Management Mode | ||
206 | 00001378808i[PCI ] setting SMRAM control register to 0x0a | ||
207 | 00001405424i[BIOS ] MP table addr=0x000fa200 MPC table addr=0x000fa130 size=0xc8 | ||
208 | 00001407131i[BIOS ] SMBIOS table addr=0x000fa210 | ||
209 | 00001409206i[BIOS ] ACPI tables: RSDP addr=0x000fa330 ACPI DATA addr=0x00ff0000 size=0xff8 | ||
210 | 00001412167i[BIOS ] Firmware waking vector 0xff00cc | ||
211 | 00001414421i[PCI ] i440FX PMC write to PAM register 59 (TLB Flush) | ||
212 | 00001415151i[BIOS ] bios_table_cur_addr: 0x000fa354 | ||
213 | 00001525858i[VBIOS ] VGABios ID: vgabios.c 2024-03-03 | ||
214 | 00001525929i[BXVGA ] VBE known Display Interface b0c0 | ||
215 | 00001525961i[BXVGA ] VBE known Display Interface b0c5 | ||
216 | 00001527382i[VBIOS ] VBE Bios ID: vbe.c 2024-03-03 | ||
217 | 00001710593i[BIOS ] ata0-0: PCHS=204/16/38 translation=none LCHS=204/16/38 | ||
218 | 00005143782i[BIOS ] IDE time out | ||
219 | 00017326769i[BIOS ] Booting from 0000:7c00 | ||
220 | 00031268476e[FLOPPY] partial read() on floppy image returns 257/512 | ||
221 | 00031312920e[FLOPPY] read() on floppy image returns 0 | ||
222 | 00031357364e[FLOPPY] read() on floppy image returns 0 | ||
223 | 00031401808e[FLOPPY] read() on floppy image returns 0 | ||
224 | 00031446252e[FLOPPY] read() on floppy image returns 0 | ||
225 | 00031490696e[FLOPPY] read() on floppy image returns 0 | ||
226 | 00031535140e[FLOPPY] read() on floppy image returns 0 | ||
227 | 00031579584e[FLOPPY] read() on floppy image returns 0 | ||
228 | 00031624028e[FLOPPY] read() on floppy image returns 0 | ||
229 | 00031668472e[FLOPPY] read() on floppy image returns 0 | ||
230 | 00031713898e[FLOPPY] read() on floppy image returns 0 | ||
231 | 00031758342e[FLOPPY] read() on floppy image returns 0 | ||
232 | 00031802786e[FLOPPY] read() on floppy image returns 0 | ||
233 | 00031847230e[FLOPPY] read() on floppy image returns 0 | ||
234 | 00031891674e[FLOPPY] read() on floppy image returns 0 | ||
235 | 00031936118e[FLOPPY] read() on floppy image returns 0 | ||
236 | 00031980562e[FLOPPY] read() on floppy image returns 0 | ||
237 | 00032025006e[FLOPPY] read() on floppy image returns 0 | ||
238 | 00032069450e[FLOPPY] read() on floppy image returns 0 | ||
239 | 00032113894e[FLOPPY] read() on floppy image returns 0 | ||
240 | 00032158338e[FLOPPY] read() on floppy image returns 0 | ||
241 | 00032202782e[FLOPPY] read() on floppy image returns 0 | ||
242 | 00032247226e[FLOPPY] read() on floppy image returns 0 | ||
243 | 00032291670e[FLOPPY] read() on floppy image returns 0 | ||
244 | 00032336114e[FLOPPY] read() on floppy image returns 0 | ||
245 | 00032380558e[FLOPPY] read() on floppy image returns 0 | ||
246 | 00032425002e[FLOPPY] read() on floppy image returns 0 | ||
247 | 00032469446e[FLOPPY] read() on floppy image returns 0 | ||
248 | 00032514867e[FLOPPY] read() on floppy image returns 0 | ||
249 | 00032559311e[FLOPPY] read() on floppy image returns 0 | ||
250 | 00032603755e[FLOPPY] read() on floppy image returns 0 | ||
251 | 00032648199e[FLOPPY] read() on floppy image returns 0 | ||
252 | 00032692643e[FLOPPY] read() on floppy image returns 0 | ||
253 | 00032737087e[FLOPPY] read() on floppy image returns 0 | ||
254 | 00032781531e[FLOPPY] read() on floppy image returns 0 | ||
255 | 00032825975e[FLOPPY] read() on floppy image returns 0 | ||
256 | 00032870419e[FLOPPY] read() on floppy image returns 0 | ||
257 | 00032914863e[FLOPPY] read() on floppy image returns 0 | ||
258 | 00032959307e[FLOPPY] read() on floppy image returns 0 | ||
259 | 00033003751e[FLOPPY] read() on floppy image returns 0 | ||
260 | 00033048195e[FLOPPY] read() on floppy image returns 0 | ||
261 | 00033092639e[FLOPPY] read() on floppy image returns 0 | ||
262 | 00033137083e[FLOPPY] read() on floppy image returns 0 | ||
263 | 00033181527e[FLOPPY] read() on floppy image returns 0 | ||
264 | 00033225971e[FLOPPY] read() on floppy image returns 0 | ||
265 | 00033270415e[FLOPPY] read() on floppy image returns 0 | ||
266 | 00033315841e[FLOPPY] read() on floppy image returns 0 | ||
267 | 00033360285e[FLOPPY] read() on floppy image returns 0 | ||
268 | 00033404729e[FLOPPY] read() on floppy image returns 0 | ||
269 | 00033449173e[FLOPPY] read() on floppy image returns 0 | ||
270 | 00033493617e[FLOPPY] read() on floppy image returns 0 | ||
271 | 00033538061e[FLOPPY] read() on floppy image returns 0 | ||
272 | 00033582505e[FLOPPY] read() on floppy image returns 0 | ||
273 | 00033626949e[FLOPPY] read() on floppy image returns 0 | ||
274 | 00033671393e[FLOPPY] read() on floppy image returns 0 | ||
275 | 00033715837e[FLOPPY] read() on floppy image returns 0 | ||
276 | 00033760281e[FLOPPY] read() on floppy image returns 0 | ||
277 | 00033804725e[FLOPPY] read() on floppy image returns 0 | ||
278 | 00033849169e[FLOPPY] read() on floppy image returns 0 | ||
279 | 00033893613e[FLOPPY] read() on floppy image returns 0 | ||
280 | 00033938057e[FLOPPY] read() on floppy image returns 0 | ||
281 | 00033982501e[FLOPPY] read() on floppy image returns 0 | ||
282 | 00034026945e[FLOPPY] read() on floppy image returns 0 | ||
283 | 00034071389e[FLOPPY] read() on floppy image returns 0 | ||
284 | 00034116818e[FLOPPY] read() on floppy image returns 0 | ||
285 | 00034161262e[FLOPPY] read() on floppy image returns 0 | ||
286 | 00034205706e[FLOPPY] read() on floppy image returns 0 | ||
287 | 00034250150e[FLOPPY] read() on floppy image returns 0 | ||
288 | 00034294594e[FLOPPY] read() on floppy image returns 0 | ||
289 | 00034339038e[FLOPPY] read() on floppy image returns 0 | ||
290 | 00034383482e[FLOPPY] read() on floppy image returns 0 | ||
291 | 00034427926e[FLOPPY] read() on floppy image returns 0 | ||
292 | 00034472370e[FLOPPY] read() on floppy image returns 0 | ||
293 | 00034516814e[FLOPPY] read() on floppy image returns 0 | ||
294 | 00034561258e[FLOPPY] read() on floppy image returns 0 | ||
295 | 00034609823i[BIOS ] int13_harddisk: function 15, unmapped device for ELDL=81 | ||
296 | 00770352000p[XGUI ] >>PANIC<< POWER button turned off. | ||
297 | 00770352000i[CPU0 ] CPU is in protected mode (active) | ||
298 | 00770352000i[CPU0 ] CS.mode = 32 bit | ||
299 | 00770352000i[CPU0 ] SS.mode = 32 bit | ||
300 | 00770352000i[CPU0 ] EFER = 0x00000000 | ||
301 | 00770352000i[CPU0 ] | EAX=00023000 EBX=00023000 ECX=00000000 EDX=00000000 | ||
302 | 00770352000i[CPU0 ] | ESP=000241a8 EBP=00027f68 ESI=000e0000 EDI=00000ffc | ||
303 | 00770352000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df IF tf sf zf af PF cf | ||
304 | 00770352000i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D | ||
305 | 00770352000i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 00ffffff 1 1 | ||
306 | 00770352000i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 00ffffff 1 1 | ||
307 | 00770352000i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 00ffffff 1 1 | ||
308 | 00770352000i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 00ffffff 1 1 | ||
309 | 00770352000i[CPU0 ] | FS:0017( 0002| 1| 3) 00000000 0009ffff 1 1 | ||
310 | 00770352000i[CPU0 ] | GS:0017( 0002| 1| 3) 00000000 0009ffff 1 1 | ||
311 | 00770352000i[CPU0 ] | EIP=00006e43 (00006e43) | ||
312 | 00770352000i[CPU0 ] | CR0=0x8000001b CR2=0x08032ef0 | ||
313 | 00770352000i[CPU0 ] | CR3=0x00000000 CR4=0x00000000 | ||
314 | 00770352000i[CMOS ] Last time: 1712615187 tz=utc (Mon Apr 8 22:26:27 2024) | ||
315 | 00770352000i[XGUI ] Exit | ||
316 | 00770352000i[SIM ] quit_sim called with exit code 1 | ||
diff --git a/dbg-bochs b/dbg-bochs new file mode 100755 index 0000000..f2ea8e9 --- /dev/null +++ b/dbg-bochs | |||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | export OSLAB_PATH=$(dirname `which $0`) | ||
4 | |||
5 | if [ ! -e "$OSLAB_PATH/hdc/umounted" ]; then | ||
6 | echo umount hdc first | ||
7 | sudo umount $OSLAB_PATH/hdc | ||
8 | if [ "$?" != "0" ]; then | ||
9 | exit | ||
10 | fi | ||
11 | fi | ||
12 | |||
13 | bochs -q -f $OSLAB_PATH/bochs/linux-0.11.bxrc | ||
diff --git a/dbg-bochsgui b/dbg-bochsgui new file mode 100755 index 0000000..ab113dd --- /dev/null +++ b/dbg-bochsgui | |||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | export OSLAB_PATH=$(dirname `which $0`) | ||
4 | |||
5 | if [ ! -e "$OSLAB_PATH/hdc/umounted" ]; then | ||
6 | echo umount hdc first | ||
7 | sudo umount $OSLAB_PATH/hdc | ||
8 | if [ "$?" != "0" ]; then | ||
9 | exit | ||
10 | fi | ||
11 | fi | ||
12 | |||
13 | bochs -q -f $OSLAB_PATH/bochs/linux-0.11-gui.bxrc | ||
diff --git a/dbg-qemu b/dbg-qemu new file mode 100755 index 0000000..700df7b --- /dev/null +++ b/dbg-qemu | |||
@@ -0,0 +1,12 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | export OSLAB_PATH=$(dirname `which $0`) | ||
4 | |||
5 | if [ "$1" == "debug" ]; then | ||
6 | debug="-s -S" | ||
7 | fi | ||
8 | |||
9 | qemu-system-i386 -m 16M -boot a \ | ||
10 | -drive file=$OSLAB_PATH/src/Image,format=raw,if=floppy \ | ||
11 | -drive file=$OSLAB_PATH/hdc-0.11.img,format=raw \ | ||
12 | $debug | ||
diff --git a/files/memtest b/files/memtest new file mode 100644 index 0000000..8c56b25 --- /dev/null +++ b/files/memtest | |||
Binary files differ | |||
diff --git a/files/process.c b/files/process.c new file mode 100644 index 0000000..46eb0b0 --- /dev/null +++ b/files/process.c | |||
@@ -0,0 +1,58 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <unistd.h> | ||
3 | #include <time.h> | ||
4 | #include <sys/times.h> | ||
5 | |||
6 | #define HZ 100 | ||
7 | |||
8 | void cpuio_bound(int last, int cpu_time, int io_time); | ||
9 | |||
10 | int main(int argc, char * argv[]) | ||
11 | { | ||
12 | return 0; | ||
13 | } | ||
14 | |||
15 | /* | ||
16 | * 此函数按照参数占用CPU和I/O时间 | ||
17 | * last: 函数实际占用CPU和I/O的总时间,不含在就绪队列中的时间,>=0是必须的 | ||
18 | * cpu_time: 一次连续占用CPU的时间,>=0是必须的 | ||
19 | * io_time: 一次I/O消耗的时间,>=0是必须的 | ||
20 | * 如果last > cpu_time + io_time,则往复多次占用CPU和I/O | ||
21 | * 所有时间的单位为秒 | ||
22 | */ | ||
23 | void cpuio_bound(int last, int cpu_time, int io_time) | ||
24 | { | ||
25 | struct tms start_time, current_time; | ||
26 | clock_t utime, stime; | ||
27 | int sleep_time; | ||
28 | |||
29 | while (last > 0) | ||
30 | { | ||
31 | /* CPU Burst */ | ||
32 | times(&start_time); | ||
33 | /* 其实只有t.tms_utime才是真正的CPU时间。但我们是在模拟一个 | ||
34 | * 只在用户状态运行的CPU大户,就像“for(;;);”。所以把t.tms_stime | ||
35 | * 加上很合理。*/ | ||
36 | do | ||
37 | { | ||
38 | times(¤t_time); | ||
39 | utime = current_time.tms_utime - start_time.tms_utime; | ||
40 | stime = current_time.tms_stime - start_time.tms_stime; | ||
41 | } while ( ( (utime + stime) / HZ ) < cpu_time ); | ||
42 | last -= cpu_time; | ||
43 | |||
44 | if (last <= 0 ) | ||
45 | break; | ||
46 | |||
47 | /* IO Burst */ | ||
48 | /* 用sleep(1)模拟1秒钟的I/O操作 */ | ||
49 | sleep_time=0; | ||
50 | while (sleep_time < io_time) | ||
51 | { | ||
52 | sleep(1); | ||
53 | sleep_time++; | ||
54 | } | ||
55 | last -= sleep_time; | ||
56 | } | ||
57 | } | ||
58 | |||
diff --git a/files/stat_log.py b/files/stat_log.py new file mode 100755 index 0000000..2dbe3ee --- /dev/null +++ b/files/stat_log.py | |||
@@ -0,0 +1,394 @@ | |||
1 | #!/usr/bin/python | ||
2 | import sys | ||
3 | import copy | ||
4 | |||
5 | P_NULL = 0 | ||
6 | P_NEW = 1 | ||
7 | P_READY = 2 | ||
8 | P_RUNNING = 4 | ||
9 | P_WAITING = 8 | ||
10 | P_EXIT = 16 | ||
11 | |||
12 | S_STATE = 0 | ||
13 | S_TIME = 1 | ||
14 | |||
15 | HZ = 100 | ||
16 | |||
17 | graph_title = r""" | ||
18 | -----===< COOL GRAPHIC OF SCHEDULER >===----- | ||
19 | |||
20 | [Symbol] [Meaning] | ||
21 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
22 | number PID or tick | ||
23 | "-" New or Exit | ||
24 | "#" Running | ||
25 | "|" Ready | ||
26 | ":" Waiting | ||
27 | / Running with | ||
28 | "+" -| Ready | ||
29 | \and/or Waiting | ||
30 | |||
31 | -----===< !!!!!!!!!!!!!!!!!!!!!!!!! >===----- | ||
32 | """ | ||
33 | |||
34 | usage = """ | ||
35 | Usage: | ||
36 | %s /path/to/process.log [PID1] [PID2] ... [-x PID1 [PID2] ... ] [-m] [-g] | ||
37 | |||
38 | Example: | ||
39 | # Include process 6, 7, 8 and 9 in statistics only. (Unit: tick) | ||
40 | %s /path/to/process.log 6 7 8 9 | ||
41 | |||
42 | # Exclude process 0 and 1 from statistics. (Unit: tick) | ||
43 | %s /path/to/process.log -x 0 1 | ||
44 | |||
45 | # Include process 6 and 7 only and print a COOL "graphic"! (Unit: millisecond) | ||
46 | %s /path/to/process.log 6 7 -m -g | ||
47 | |||
48 | # Include all processes and print a COOL "graphic"! (Unit: tick) | ||
49 | %s /path/to/process.log -g | ||
50 | """ | ||
51 | |||
52 | class MyError(Exception): | ||
53 | pass | ||
54 | |||
55 | class DuplicateNew(MyError): | ||
56 | def __init__(self, pid): | ||
57 | args = "More than one 'N' for process %d." % pid | ||
58 | MyError.__init__(self, args) | ||
59 | |||
60 | class UnknownState(MyError): | ||
61 | def __init__(self, state): | ||
62 | args = "Unknown state '%s' found." % state | ||
63 | MyError.__init__(self, args) | ||
64 | |||
65 | class BadTime(MyError): | ||
66 | def __init__(self, time): | ||
67 | args = "The time '%d' is bad. It should >= previous line's time." % time | ||
68 | MyError.__init__(self, args) | ||
69 | |||
70 | class TaskHasExited(MyError): | ||
71 | def __init__(self, state): | ||
72 | args = "The process has exited. Why it enter '%s' state again?" % state | ||
73 | MyError.__init__(self, args) | ||
74 | |||
75 | class BadFormat(MyError): | ||
76 | def __init__(self): | ||
77 | args = "Bad log format" | ||
78 | MyError.__init__(self, args) | ||
79 | |||
80 | class RepeatState(MyError): | ||
81 | def __init__(self, pid): | ||
82 | args = "Previous state of process %d is identical with this line." % (pid) | ||
83 | MyError.__init__(self, args) | ||
84 | |||
85 | class SameLine(MyError): | ||
86 | def __init__(self): | ||
87 | args = "It is a clone of previous line." | ||
88 | MyError.__init__(self, args) | ||
89 | |||
90 | class NoNew(MyError): | ||
91 | def __init__(self, pid, state): | ||
92 | args = "The first state of process %d is '%s'. Why not 'N'?" % (pid, state) | ||
93 | MyError.__init__(self, args) | ||
94 | |||
95 | class statistics: | ||
96 | def __init__(self, pool, include, exclude): | ||
97 | if include: | ||
98 | self.pool = process_pool() | ||
99 | for process in pool: | ||
100 | if process.getpid() in include: | ||
101 | self.pool.add(process) | ||
102 | else: | ||
103 | self.pool = copy.copy(pool) | ||
104 | |||
105 | if exclude: | ||
106 | for pid in exclude: | ||
107 | if self.pool.get_process(pid): | ||
108 | self.pool.remove(pid) | ||
109 | |||
110 | def list_pid(self): | ||
111 | l = [] | ||
112 | for process in self.pool: | ||
113 | l.append(process.getpid()) | ||
114 | return l | ||
115 | |||
116 | def average_turnaround(self): | ||
117 | if len(self.pool) == 0: | ||
118 | return 0 | ||
119 | sum = 0 | ||
120 | for process in self.pool: | ||
121 | sum += process.turnaround_time() | ||
122 | return float(sum) / len(self.pool) | ||
123 | |||
124 | def average_waiting(self): | ||
125 | if len(self.pool) == 0: | ||
126 | return 0 | ||
127 | sum = 0 | ||
128 | for process in self.pool: | ||
129 | sum += process.waiting_time() | ||
130 | return float(sum) / len(self.pool) | ||
131 | |||
132 | def begin_time(self): | ||
133 | begin = 0xEFFFFF | ||
134 | for p in self.pool: | ||
135 | if p.begin_time() < begin: | ||
136 | begin = p.begin_time() | ||
137 | return begin | ||
138 | |||
139 | def end_time(self): | ||
140 | end = 0 | ||
141 | for p in self.pool: | ||
142 | if p.end_time() > end: | ||
143 | end = p.end_time() | ||
144 | return end | ||
145 | |||
146 | def throughput(self): | ||
147 | return len(self.pool) * HZ / float(self.end_time() - self.begin_time()) | ||
148 | |||
149 | def print_graphic(self): | ||
150 | begin = self.begin_time() | ||
151 | end = self.end_time() | ||
152 | |||
153 | print graph_title | ||
154 | |||
155 | for i in range(begin, end+1): | ||
156 | line = "%5d " % i | ||
157 | for p in self.pool: | ||
158 | state = p.get_state(i) | ||
159 | if state & P_NEW: | ||
160 | line += "-" | ||
161 | elif state == P_READY or state == P_READY | P_WAITING: | ||
162 | line += "|" | ||
163 | elif state == P_RUNNING: | ||
164 | line += "#" | ||
165 | elif state == P_WAITING: | ||
166 | line += ":" | ||
167 | elif state & P_EXIT: | ||
168 | line += "-" | ||
169 | elif state == P_NULL: | ||
170 | line += " " | ||
171 | elif state & P_RUNNING: | ||
172 | line += "+" | ||
173 | else: | ||
174 | assert False | ||
175 | if p.get_state(i-1) != state and state != P_NULL: | ||
176 | line += "%-3d" % p.getpid() | ||
177 | else: | ||
178 | line += " " | ||
179 | print line | ||
180 | |||
181 | class process_pool: | ||
182 | def __init__(self): | ||
183 | self.list = [] | ||
184 | |||
185 | def get_process(self, pid): | ||
186 | for process in self.list: | ||
187 | if process.getpid() == pid: | ||
188 | return process | ||
189 | return None | ||
190 | |||
191 | def remove(self, pid): | ||
192 | for process in self.list: | ||
193 | if process.getpid() == pid: | ||
194 | self.list.remove(process) | ||
195 | |||
196 | def new(self, pid, time): | ||
197 | p = self.get_process(pid) | ||
198 | if p: | ||
199 | if pid != 0: | ||
200 | raise DuplicateNew(pid) | ||
201 | else: | ||
202 | p.states=[(P_NEW, time)] | ||
203 | else: | ||
204 | p = process(pid, time) | ||
205 | self.list.append(p) | ||
206 | return p | ||
207 | |||
208 | def add(self, p): | ||
209 | self.list.append(p) | ||
210 | |||
211 | def __len__(self): | ||
212 | return len(self.list) | ||
213 | |||
214 | def __iter__(self): | ||
215 | return iter(self.list) | ||
216 | |||
217 | class process: | ||
218 | def __init__(self, pid, time): | ||
219 | self.pid = pid | ||
220 | self.states = [(P_NEW, time)] | ||
221 | |||
222 | def getpid(self): | ||
223 | return self.pid | ||
224 | |||
225 | def change_state(self, state, time): | ||
226 | last_state, last_time = self.states[-1] | ||
227 | if state == P_NEW: | ||
228 | raise DuplicateNew(pid) | ||
229 | if time < last_time: | ||
230 | raise BadTime(time) | ||
231 | if last_state == P_EXIT: | ||
232 | raise TaskHasExited(state) | ||
233 | if last_state == state and self.pid != 0: # task 0 can have duplicate state | ||
234 | raise RepeatState(self.pid) | ||
235 | |||
236 | self.states.append((state, time)) | ||
237 | |||
238 | def get_state(self, time): | ||
239 | rval = P_NULL | ||
240 | combo = P_NULL | ||
241 | if self.begin_time() <= time <= self.end_time(): | ||
242 | for state, s_time in self.states: | ||
243 | if s_time < time: | ||
244 | rval = state | ||
245 | elif s_time == time: | ||
246 | combo |= state | ||
247 | else: | ||
248 | break | ||
249 | if combo: | ||
250 | rval = combo | ||
251 | return rval | ||
252 | |||
253 | def turnaround_time(self): | ||
254 | return self.states[-1][S_TIME] - self.states[0][S_TIME] | ||
255 | |||
256 | def waiting_time(self): | ||
257 | return self.state_last_time(P_READY) | ||
258 | |||
259 | def cpu_time(self): | ||
260 | return self.state_last_time(P_RUNNING) | ||
261 | |||
262 | def io_time(self): | ||
263 | return self.state_last_time(P_WAITING) | ||
264 | |||
265 | def state_last_time(self, state): | ||
266 | time = 0 | ||
267 | state_begin = 0 | ||
268 | for s,t in self.states: | ||
269 | if s == state: | ||
270 | state_begin = t | ||
271 | elif state_begin != 0: | ||
272 | assert state_begin <= t | ||
273 | time += t - state_begin | ||
274 | state_begin = 0 | ||
275 | return time | ||
276 | |||
277 | |||
278 | def begin_time(self): | ||
279 | return self.states[0][S_TIME] | ||
280 | |||
281 | def end_time(self): | ||
282 | return self.states[-1][S_TIME] | ||
283 | |||
284 | # Enter point | ||
285 | if len(sys.argv) < 2: | ||
286 | print usage.replace("%s", sys.argv[0]) | ||
287 | sys.exit(0) | ||
288 | |||
289 | # parse arguments | ||
290 | include = [] | ||
291 | exclude = [] | ||
292 | unit_ms = False | ||
293 | graphic = False | ||
294 | ex_mark = False | ||
295 | |||
296 | try: | ||
297 | for arg in sys.argv[2:]: | ||
298 | if arg == '-m': | ||
299 | unit_ms = True | ||
300 | continue | ||
301 | if arg == '-g': | ||
302 | graphic = True | ||
303 | continue | ||
304 | if not ex_mark: | ||
305 | if arg == '-x': | ||
306 | ex_mark = True | ||
307 | else: | ||
308 | include.append(int(arg)) | ||
309 | else: | ||
310 | exclude.append(int(arg)) | ||
311 | except ValueError: | ||
312 | print "Bad argument '%s'" % arg | ||
313 | sys.exit(-1) | ||
314 | |||
315 | # parse log file and construct processes | ||
316 | processes = process_pool() | ||
317 | |||
318 | f = open(sys.argv[1], "r") | ||
319 | |||
320 | # Patch process 0's New & Run state | ||
321 | processes.new(0, 40).change_state(P_RUNNING, 40) | ||
322 | |||
323 | try: | ||
324 | prev_time = 0 | ||
325 | prev_line = "" | ||
326 | for lineno, line in enumerate(f): | ||
327 | |||
328 | if line == prev_line: | ||
329 | raise SameLine | ||
330 | prev_line = line | ||
331 | |||
332 | fields = line.split("\t") | ||
333 | if len(fields) != 3: | ||
334 | raise BadFormat | ||
335 | |||
336 | pid = int(fields[0]) | ||
337 | s = fields[1].upper() | ||
338 | |||
339 | time = int(fields[2]) | ||
340 | if time < prev_time: | ||
341 | raise BadTime(time) | ||
342 | prev_time = time | ||
343 | |||
344 | p = processes.get_process(pid) | ||
345 | |||
346 | state = P_NULL | ||
347 | if s == 'N': | ||
348 | processes.new(pid, time) | ||
349 | elif s == 'J': | ||
350 | state = P_READY | ||
351 | elif s == 'R': | ||
352 | state = P_RUNNING | ||
353 | elif s == 'W': | ||
354 | state = P_WAITING | ||
355 | elif s == 'E': | ||
356 | state = P_EXIT | ||
357 | else: | ||
358 | raise UnknownState(s) | ||
359 | if state != P_NULL: | ||
360 | if not p: | ||
361 | raise NoNew(pid, s) | ||
362 | p.change_state(state, time) | ||
363 | except MyError, err: | ||
364 | print "Error at line %d: %s" % (lineno+1, err) | ||
365 | sys.exit(0) | ||
366 | |||
367 | # Stats | ||
368 | stats = statistics(processes, include, exclude) | ||
369 | att = stats.average_turnaround() | ||
370 | awt = stats.average_waiting() | ||
371 | if unit_ms: | ||
372 | unit = "ms" | ||
373 | att *= 1000/HZ | ||
374 | awt *= 1000/HZ | ||
375 | else: | ||
376 | unit = "tick" | ||
377 | print "(Unit: %s)" % unit | ||
378 | print "Process Turnaround Waiting CPU Burst I/O Burst" | ||
379 | for pid in stats.list_pid(): | ||
380 | p = processes.get_process(pid) | ||
381 | tt = p.turnaround_time() | ||
382 | wt = p.waiting_time() | ||
383 | cpu = p.cpu_time() | ||
384 | io = p.io_time() | ||
385 | |||
386 | if unit_ms: | ||
387 | print "%7d %10d %7d %9d %9d" % (pid, tt*1000/HZ, wt*1000/HZ, cpu*1000/HZ, io*1000/HZ) | ||
388 | else: | ||
389 | print "%7d %10d %7d %9d %9d" % (pid, tt, wt, cpu, io) | ||
390 | print "Average: %10.2f %7.2f" % (att, awt) | ||
391 | print "Throughout: %.2f/s" % (stats.throughput()) | ||
392 | |||
393 | if graphic: | ||
394 | stats.print_graphic() | ||
diff --git a/files/testlab2.c b/files/testlab2.c new file mode 100644 index 0000000..bd97b76 --- /dev/null +++ b/files/testlab2.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * Compile: "gcc testlab2.c" | ||
3 | * Run: "./a.out" | ||
4 | */ | ||
5 | |||
6 | #include <string.h> | ||
7 | #include <assert.h> | ||
8 | #include <stdio.h> | ||
9 | #include <errno.h> | ||
10 | #include <stdlib.h> | ||
11 | #define __LIBRARY__ | ||
12 | #include <unistd.h> | ||
13 | |||
14 | _syscall2(int, whoami,char*,name,unsigned int,size); | ||
15 | _syscall1(int, iam, const char*, name); | ||
16 | |||
17 | #define MAX_NAME_LEN 23 | ||
18 | #define NAMEBUF_SIZE (MAX_NAME_LEN + 1) | ||
19 | /* truncate a long name to SHORT_NAME_LEN for display */ | ||
20 | #define SHORT_NAME_LEN (MAX_NAME_LEN + 2) | ||
21 | |||
22 | /* name score */ | ||
23 | #define TEST_CASE { \ | ||
24 | {"x", 10, 1, NAMEBUF_SIZE, 1},\ | ||
25 | {"sunner", 10, 6, NAMEBUF_SIZE, 6},\ | ||
26 | {"Twenty-three characters", 5, 23, NAMEBUF_SIZE, 23},\ | ||
27 | {"123456789009876543211234", 5, -1, 0, -1},\ | ||
28 | {"abcdefghijklmnopqrstuvwxyz", 5, -1, 0, -1},\ | ||
29 | {"Linus Torvalds", 5, 14, NAMEBUF_SIZE, 14},\ | ||
30 | {"", 5, 0, NAMEBUF_SIZE, 0},\ | ||
31 | {"whoami(0xbalabala, 10)", 5, 22, 10, -1},\ | ||
32 | {NULL, 0, 0, 0, 0} /* End of cases */ \ | ||
33 | } | ||
34 | /*改动一:增加size,和rval2*/ | ||
35 | |||
36 | int test(const char* name, int max_score, int expected_rval1, int size, int expected_rval2); | ||
37 | void print_message(const char* msgfmt, const char* name); | ||
38 | |||
39 | struct test_case | ||
40 | { | ||
41 | char *name; | ||
42 | int score; | ||
43 | int rval1; /* return value of iam() */ | ||
44 | /*改动2:增加size,和rval2定义*/ | ||
45 | int size; /*Patch for whoami,2009.11.2*/ | ||
46 | int rval2; /* return value of whoami() */ | ||
47 | }; | ||
48 | |||
49 | int main(void) | ||
50 | { | ||
51 | struct test_case cases[] = TEST_CASE; | ||
52 | |||
53 | int total_score=0, i=0; | ||
54 | |||
55 | while (cases[i].score != 0) | ||
56 | { | ||
57 | int score; | ||
58 | |||
59 | printf("Test case %d:", i+1); | ||
60 | |||
61 | /*改动3:增加size,和rval2的参数阿*/ | ||
62 | score = test( cases[i].name, | ||
63 | cases[i].score, | ||
64 | cases[i].rval1, | ||
65 | cases[i].size, | ||
66 | cases[i].rval2 ); | ||
67 | |||
68 | total_score += score; | ||
69 | i++; | ||
70 | } | ||
71 | |||
72 | printf("Final result: %d%%\n", total_score); | ||
73 | return 0; | ||
74 | |||
75 | } | ||
76 | /*改动4:增加size,和rval2的声明*/ | ||
77 | int test(const char* name, int max_score, int expected_rval1, int size, int expected_rval2) | ||
78 | { | ||
79 | int rval; | ||
80 | int len; | ||
81 | char * gotname; | ||
82 | int score=-1; | ||
83 | |||
84 | assert(name != NULL); | ||
85 | |||
86 | print_message("name = \"%s\", length = %d...", name); | ||
87 | |||
88 | /*Test iam()*/ | ||
89 | len = strlen(name); | ||
90 | rval = iam(name); | ||
91 | /* printf("Return value = %d\n", rval);*/ | ||
92 | |||
93 | /*改动5:增加的expected_rval1*/ | ||
94 | if (rval == expected_rval1) | ||
95 | { | ||
96 | if (rval == -1 && errno == EINVAL) /*The system call can detect bad name*/ | ||
97 | { | ||
98 | /* print_message("Long name, %s(%d), detected.\n", name);*/ | ||
99 | printf("PASS\n"); | ||
100 | score = max_score; | ||
101 | } | ||
102 | else if (rval == -1 && errno != EINVAL) | ||
103 | { | ||
104 | printf("\nERROR iam(): Bad errno %d. It should be %d(EINVAL).\n", errno, EINVAL); | ||
105 | score = 0; | ||
106 | } | ||
107 | /* iam() is good. Test whoami() next. */ | ||
108 | } | ||
109 | else | ||
110 | { | ||
111 | printf("\nERROR iam(): Return value is %d. It should be %d.\n", rval, expected_rval1); | ||
112 | score = 0; | ||
113 | } | ||
114 | |||
115 | if (score != -1) | ||
116 | return score; | ||
117 | |||
118 | /*Test whoami()*/ | ||
119 | gotname = (char*)malloc(len+1); | ||
120 | if (gotname == NULL) | ||
121 | exit(-1); | ||
122 | |||
123 | memset(gotname, 0, len+1); | ||
124 | |||
125 | /* printf("Get: buffer length = %d.\n", len+1); */ | ||
126 | |||
127 | rval = whoami(gotname, size); | ||
128 | /* printf("Return value = %d\n", rval); */ | ||
129 | |||
130 | /*改动6:增加的expected_rval2*/ | ||
131 | /*改动++:比较多 ,但还是顺序的改改*/ | ||
132 | |||
133 | if(rval == expected_rval2) | ||
134 | { | ||
135 | if(rval == -1) | ||
136 | { | ||
137 | printf("PASS\n"); | ||
138 | score = max_score; | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | if (strcmp(gotname, name) == 0) | ||
143 | { | ||
144 | /* print_message("Great! We got %s(%d) finally!\n", gotname); */ | ||
145 | printf("PASS\n"); | ||
146 | score = max_score; | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | print_message("\nERROR whoami(): we got %s(%d). ", gotname); | ||
151 | print_message("It should be %s(%d).\n", name); | ||
152 | score = 0; | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | else if (rval == -1) | ||
157 | { | ||
158 | printf("\nERROR whoami(): Return value is -1 and errno is %d. Why?\n", errno); | ||
159 | score = 0; | ||
160 | } | ||
161 | else | ||
162 | { | ||
163 | printf("\nERROR whoami(): Return value should be %d, not %d.\n", expected_rval2, rval); | ||
164 | score = 0; | ||
165 | } | ||
166 | |||
167 | free(gotname); | ||
168 | assert(score != -1); | ||
169 | |||
170 | return score; | ||
171 | } | ||
172 | |||
173 | void print_message(const char* msgfmt, const char* name) | ||
174 | { | ||
175 | char short_name[SHORT_NAME_LEN + 4] = {0}; | ||
176 | int len; | ||
177 | |||
178 | len = strlen(name); | ||
179 | |||
180 | if (len == 0) | ||
181 | { | ||
182 | strcpy(short_name, "NULL"); | ||
183 | } | ||
184 | else if (len <= SHORT_NAME_LEN) | ||
185 | { | ||
186 | strcpy(short_name, name); | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | memset(short_name, '.', SHORT_NAME_LEN+3); | ||
191 | memcpy(short_name, name, SHORT_NAME_LEN); | ||
192 | } | ||
193 | |||
194 | printf(msgfmt, short_name, len); | ||
195 | } | ||
diff --git a/files/testlab2.sh b/files/testlab2.sh new file mode 100755 index 0000000..7f79876 --- /dev/null +++ b/files/testlab2.sh | |||
@@ -0,0 +1,49 @@ | |||
1 | #/bin/sh | ||
2 | |||
3 | string1="Sunner" | ||
4 | string2="Richard Stallman" | ||
5 | string3="This is a very very long string!" | ||
6 | |||
7 | score1=10 | ||
8 | score2=10 | ||
9 | score3=10 | ||
10 | |||
11 | expected1="Sunner" | ||
12 | expected2="Richard Stallman" | ||
13 | expected3="Richard Stallman" | ||
14 | |||
15 | echo Testing string:$string1 | ||
16 | ./iam "$string1" | ||
17 | result=`./whoami` | ||
18 | if [ "$result" = "$expected1" ]; then | ||
19 | echo PASS. | ||
20 | else | ||
21 | score1=0 | ||
22 | echo FAILED. | ||
23 | fi | ||
24 | score=$score1 | ||
25 | |||
26 | echo Testing string:$string2 | ||
27 | ./iam "$string2" | ||
28 | result=`./whoami` | ||
29 | if [ "$result" = "$expected2" ]; then | ||
30 | echo PASS. | ||
31 | else | ||
32 | score2=0 | ||
33 | echo FAILED. | ||
34 | fi | ||
35 | score=$score+$score2 | ||
36 | |||
37 | echo Testing string:$string3 | ||
38 | ./iam "$string3" | ||
39 | result=`./whoami` | ||
40 | if [ "$result" = "$expected3" ]; then | ||
41 | echo PASS. | ||
42 | else | ||
43 | score3=0 | ||
44 | echo FAILED. | ||
45 | fi | ||
46 | score=$score+$score3 | ||
47 | |||
48 | let "totalscore=$score" | ||
49 | echo Score: $score = $totalscore% | ||
diff --git a/gdb-cmd.txt b/gdb-cmd.txt new file mode 100644 index 0000000..53d5d44 --- /dev/null +++ b/gdb-cmd.txt | |||
@@ -0,0 +1,7 @@ | |||
1 | target remote localhost:1234 | ||
2 | b main | ||
3 | handle all nostop noprint | ||
4 | set print pretty on | ||
5 | set print array-indexes on | ||
6 | c | ||
7 | layout src | ||
diff --git a/hdc-0.11.img b/hdc-0.11.img new file mode 100644 index 0000000..49585cf --- /dev/null +++ b/hdc-0.11.img | |||
Binary files differ | |||
diff --git a/hdc/umounted b/hdc/umounted new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/hdc/umounted | |||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/sh | ||
2 | export OSLAB_PATH=$(dirname `which $0`) | ||
3 | |||
4 | if [ -f $OSLAB_PATH/linux-0.11.tar.gz ]; then | ||
5 | [ -d $OSLAB_PATH/linux-0.11 ] && rm -rf $OSLAB_PATH/src | ||
6 | mkdir $OSLAB_PATH/linux-0.11 | ||
7 | tar zxf $OSLAB_PATH/src.tar.gz -C $OSLAB_PATH/src | ||
8 | echo "Successfully recover linux-0.11." | ||
9 | exit 0 | ||
10 | else | ||
11 | echo "Error: oslab cant't find a backup file named linux-0.11.tar.gz!" | ||
12 | exit 1 | ||
13 | fi | ||
diff --git a/mount-hdc b/mount-hdc new file mode 100755 index 0000000..57d8430 --- /dev/null +++ b/mount-hdc | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | export OSLAB_PATH=$(dirname `which $0`) | ||
3 | sudo mount -t minix -o loop,offset=1024 $OSLAB_PATH/hdc-0.11.img $OSLAB_PATH/hdc | ||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | export OSLAB_PATH=$(dirname `which $0`) | ||
4 | |||
5 | if [ ! -e "$OSLAB_PATH/hdc/umounted" ]; then | ||
6 | echo umount hdc first | ||
7 | sudo umount $OSLAB_PATH/hdc | ||
8 | if [ "$?" != "0" ]; then | ||
9 | exit | ||
10 | fi | ||
11 | fi | ||
12 | |||
13 | gdb -x $OSLAB_PATH/gdb-cmd.txt $OSLAB_PATH/src/tools/system | ||
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..581dbeb --- /dev/null +++ b/src/Makefile | |||
@@ -0,0 +1,132 @@ | |||
1 | # if you want the ram-disk device, define this to be the | ||
2 | # size in blocks. | ||
3 | # | ||
4 | RAMDISK = #-DRAMDISK=512 | ||
5 | |||
6 | # This is a basic Makefile for setting the general configuration | ||
7 | include Makefile.header | ||
8 | |||
9 | LDFLAGS += -Ttext 0 -e startup_32 | ||
10 | CFLAGS += $(RAMDISK) -Iinclude | ||
11 | CPP += -Iinclude | ||
12 | |||
13 | # | ||
14 | # ROOT_DEV specifies the default root-device when making the image. | ||
15 | # This can be either FLOPPY, /dev/xxxx or empty, in which case the | ||
16 | # default of /dev/hd6 is used by 'build'. | ||
17 | # | ||
18 | ROOT_DEV= #FLOPPY | ||
19 | |||
20 | ARCHIVES=kernel/kernel.o mm/mm.o fs/fs.o | ||
21 | DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a | ||
22 | MATH =kernel/math/math.a | ||
23 | LIBS =lib/lib.a | ||
24 | |||
25 | .c.s: | ||
26 | @$(CC) $(CFLAGS) -S -o $*.s $< | ||
27 | .s.o: | ||
28 | @$(AS) -o $*.o $< | ||
29 | .c.o: | ||
30 | @$(CC) $(CFLAGS) -c -o $*.o $< | ||
31 | |||
32 | all: Image | ||
33 | |||
34 | Image: boot/bootsect boot/setup tools/system | ||
35 | @cp -f tools/system system.tmp | ||
36 | @$(STRIP) system.tmp | ||
37 | @$(OBJCOPY) -O binary -R .note -R .comment -R .note.gnu.property system.tmp tools/kernel | ||
38 | @tools/build.sh boot/bootsect boot/setup tools/kernel Image $(ROOT_DEV) | ||
39 | @rm system.tmp | ||
40 | @rm -f tools/kernel | ||
41 | @sync | ||
42 | |||
43 | disk: Image | ||
44 | @dd bs=8192 if=Image of=/dev/fd0 | ||
45 | |||
46 | boot/head.o: boot/head.s | ||
47 | @make head.o -C boot/ | ||
48 | |||
49 | tools/system: boot/head.o init/main.o \ | ||
50 | $(ARCHIVES) $(DRIVERS) $(MATH) $(LIBS) | ||
51 | @$(LD) $(LDFLAGS) boot/head.o init/main.o \ | ||
52 | $(ARCHIVES) \ | ||
53 | $(DRIVERS) \ | ||
54 | $(MATH) \ | ||
55 | $(LIBS) \ | ||
56 | -o tools/system | ||
57 | @nm tools/system | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)'| sort > System.map | ||
58 | |||
59 | kernel/math/math.a: | ||
60 | @make -C kernel/math | ||
61 | |||
62 | kernel/blk_drv/blk_drv.a: | ||
63 | @make -C kernel/blk_drv | ||
64 | |||
65 | kernel/chr_drv/chr_drv.a: | ||
66 | @make -C kernel/chr_drv | ||
67 | |||
68 | kernel/kernel.o: | ||
69 | @make -C kernel | ||
70 | |||
71 | mm/mm.o: | ||
72 | @make -C mm | ||
73 | |||
74 | fs/fs.o: | ||
75 | @make -C fs | ||
76 | |||
77 | lib/lib.a: | ||
78 | @make -C lib | ||
79 | |||
80 | boot/setup: boot/setup.s | ||
81 | @make setup -C boot | ||
82 | |||
83 | boot/bootsect: boot/bootsect.s | ||
84 | @make bootsect -C boot | ||
85 | |||
86 | tmp.s: boot/bootsect.s tools/system | ||
87 | @(echo -n "SYSSIZE = (";ls -l tools/system | grep system \ | ||
88 | | cut -c25-31 | tr '\012' ' '; echo "+ 15 ) / 16") > tmp.s | ||
89 | @cat boot/bootsect.s >> tmp.s | ||
90 | |||
91 | clean: | ||
92 | @rm -f Image System.map tmp_make core boot/bootsect boot/setup | ||
93 | @rm -f init/*.o tools/system boot/*.o typescript* info bochsout.txt | ||
94 | @for i in mm fs kernel lib boot; do make clean -C $$i; done | ||
95 | info: | ||
96 | @make clean | ||
97 | @script -q -c "make all" | ||
98 | @cat typescript | col -bp | grep -E "warning|Error" > info | ||
99 | @cat info | ||
100 | |||
101 | distclean: clean | ||
102 | @rm -f tag cscope* linux-0.11.* $(CALLTREE) | ||
103 | @(find tools/calltree-2.3 -name "*.o" | xargs -i rm -f {}) | ||
104 | @make clean -C tools/calltree-2.3 | ||
105 | @make clean -C tools/bochs/bochs-2.3.7 | ||
106 | |||
107 | backup: clean | ||
108 | @(cd .. ; tar cf - linux | compress16 - > backup.Z) | ||
109 | @sync | ||
110 | |||
111 | dep: | ||
112 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
113 | @(for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done) >> tmp_make | ||
114 | @cp tmp_make Makefile | ||
115 | @for i in fs kernel mm; do make dep -C $$i; done | ||
116 | |||
117 | tag: tags | ||
118 | tags: | ||
119 | @ctags -R | ||
120 | |||
121 | cscope: | ||
122 | @cscope -Rbkq | ||
123 | |||
124 | |||
125 | |||
126 | ### Dependencies: | ||
127 | init/main.o: init/main.c include/unistd.h include/sys/stat.h \ | ||
128 | include/sys/types.h include/sys/times.h include/sys/utsname.h \ | ||
129 | include/utime.h include/time.h include/linux/tty.h include/termios.h \ | ||
130 | include/linux/sched.h include/linux/head.h include/linux/fs.h \ | ||
131 | include/linux/mm.h include/signal.h include/asm/system.h \ | ||
132 | include/asm/io.h include/stddef.h include/stdarg.h include/fcntl.h | ||
diff --git a/src/Makefile.header b/src/Makefile.header new file mode 100644 index 0000000..a9e6aa3 --- /dev/null +++ b/src/Makefile.header | |||
@@ -0,0 +1,41 @@ | |||
1 | UNAME := $(shell uname) | ||
2 | |||
3 | ifeq ($(UNAME), Linux) | ||
4 | AS = as --32 | ||
5 | LD = ld | ||
6 | #LDFLAGS = -m elf_i386 -x | ||
7 | LDFLAGS = -m elf_i386 | ||
8 | CC = gcc | ||
9 | CFLAGS = -g -m32 \ | ||
10 | -fno-builtin -fno-stack-protector \ | ||
11 | -fomit-frame-pointer -fstrength-reduce \ | ||
12 | -Wno-implicit-int \ | ||
13 | -Wno-implicit-function-declaration \ | ||
14 | -Wno-int-conversion \ | ||
15 | -mno-sse -mno-sse2 | ||
16 | |||
17 | CPP = cpp -nostdinc | ||
18 | AR = ar | ||
19 | STRIP = strip | ||
20 | OBJCOPY = objcopy | ||
21 | # we should use -fno-stack-protector with gcc 4.3 | ||
22 | gcc_version=$(shell ls -l `which gcc` | tr '-' '\n' | tail -1) | ||
23 | endif | ||
24 | |||
25 | |||
26 | |||
27 | ifeq ($(UNAME), Darwin) | ||
28 | AS = i386-elf-as --32 | ||
29 | LD = i386-elf-ld | ||
30 | #LDFLAGS = -m elf_i386 -x | ||
31 | LDFLAGS = -m elf_i386 | ||
32 | CC = i386-elf-gcc-4.3.2 | ||
33 | CFLAGS = -gdwarf-2 -g3 -m32 -fno-builtin -fno-stack-protector -fomit-frame-pointer -fstrength-reduce #-Wall | ||
34 | |||
35 | CPP = i386-elf-cpp-4.3.2 -nostdinc | ||
36 | AR =i386-elf-ar | ||
37 | STRIP = i386-elf-strip | ||
38 | OBJCOPY = i386-elf-objcopy | ||
39 | endif | ||
40 | |||
41 | |||
diff --git a/src/boot/Makefile b/src/boot/Makefile new file mode 100644 index 0000000..df0c5a0 --- /dev/null +++ b/src/boot/Makefile | |||
@@ -0,0 +1,22 @@ | |||
1 | include ../Makefile.header | ||
2 | |||
3 | LDFLAGS += -Ttext 0 | ||
4 | |||
5 | all: bootsect setup | ||
6 | |||
7 | bootsect: bootsect.s | ||
8 | @$(AS) -o bootsect.o bootsect.s | ||
9 | @$(LD) $(LDFLAGS) -o bootsect bootsect.o | ||
10 | @$(OBJCOPY) -R .pdr -R .comment -R.note -S -O binary bootsect | ||
11 | |||
12 | |||
13 | setup: setup.s | ||
14 | @$(AS) -o setup.o setup.s | ||
15 | @$(LD) $(LDFLAGS) -o setup setup.o | ||
16 | @$(OBJCOPY) -R .pdr -R .comment -R.note -S -O binary setup | ||
17 | |||
18 | head.o: head.s | ||
19 | @$(AS) -o head.o head.s | ||
20 | |||
21 | clean: | ||
22 | @rm -f bootsect bootsect.o setup setup.o head.o | ||
diff --git a/src/boot/bootsect.s b/src/boot/bootsect.s new file mode 100644 index 0000000..94b1114 --- /dev/null +++ b/src/boot/bootsect.s | |||
@@ -0,0 +1,263 @@ | |||
1 | .code16 | ||
2 | # rewrite with AT&T syntax by falcon <wuzhangjin@gmail.com> at 081012 | ||
3 | # | ||
4 | # SYS_SIZE is the number of clicks (16 bytes) to be loaded. | ||
5 | # 0x3000 is 0x30000 bytes = 196kB, more than enough for current | ||
6 | # versions of linux | ||
7 | # | ||
8 | .equ SYSSIZE, 0x3000 | ||
9 | # | ||
10 | # bootsect.s (C) 1991 Linus Torvalds | ||
11 | # | ||
12 | # bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves | ||
13 | # iself out of the way to address 0x90000, and jumps there. | ||
14 | # | ||
15 | # It then loads 'setup' directly after itself (0x90200), and the system | ||
16 | # at 0x10000, using BIOS interrupts. | ||
17 | # | ||
18 | # NOTE! currently system is at most 8*65536 bytes long. This should be no | ||
19 | # problem, even in the future. I want to keep it simple. This 512 kB | ||
20 | # kernel size should be enough, especially as this doesn't contain the | ||
21 | # buffer cache as in minix | ||
22 | # | ||
23 | # The loader has been made as simple as possible, and continuos | ||
24 | # read errors will result in a unbreakable loop. Reboot by hand. It | ||
25 | # loads pretty fast by getting whole sectors at a time whenever possible. | ||
26 | |||
27 | .global _start, begtext, begdata, begbss, endtext, enddata, endbss | ||
28 | .text | ||
29 | begtext: | ||
30 | .data | ||
31 | begdata: | ||
32 | .bss | ||
33 | begbss: | ||
34 | .text | ||
35 | |||
36 | .equ SETUPLEN, 4 # nr of setup-sectors | ||
37 | .equ BOOTSEG, 0x07c0 # original address of boot-sector | ||
38 | .equ INITSEG, 0x9000 # we move boot here - out of the way | ||
39 | .equ SETUPSEG, 0x9020 # setup starts here | ||
40 | .equ SYSSEG, 0x1000 # system loaded at 0x10000 (65536). | ||
41 | .equ ENDSEG, SYSSEG + SYSSIZE # where to stop loading | ||
42 | |||
43 | # ROOT_DEV: 0x000 - same type of floppy as boot. | ||
44 | # 0x301 - first partition on first drive etc | ||
45 | .equ ROOT_DEV, 0x301 | ||
46 | ljmp $BOOTSEG, $_start | ||
47 | _start: | ||
48 | mov $BOOTSEG, %ax | ||
49 | mov %ax, %ds | ||
50 | mov $INITSEG, %ax | ||
51 | mov %ax, %es | ||
52 | mov $256, %cx | ||
53 | sub %si, %si | ||
54 | sub %di, %di | ||
55 | rep | ||
56 | movsw | ||
57 | ljmp $INITSEG, $go | ||
58 | go: mov %cs, %ax | ||
59 | mov %ax, %ds | ||
60 | mov %ax, %es | ||
61 | # put stack at 0x9ff00. | ||
62 | mov %ax, %ss | ||
63 | mov $0xFF00, %sp # arbitrary value >>512 | ||
64 | |||
65 | # load the setup-sectors directly after the bootblock. | ||
66 | # Note that 'es' is already set up. | ||
67 | |||
68 | load_setup: | ||
69 | mov $0x0000, %dx # drive 0, head 0 | ||
70 | mov $0x0002, %cx # sector 2, track 0 | ||
71 | mov $0x0200, %bx # address = 512, in INITSEG | ||
72 | .equ AX, 0x0200+SETUPLEN | ||
73 | mov $AX, %ax # service 2, nr of sectors | ||
74 | int $0x13 # read it | ||
75 | jnc ok_load_setup # ok - continue | ||
76 | mov $0x0000, %dx | ||
77 | mov $0x0000, %ax # reset the diskette | ||
78 | int $0x13 | ||
79 | jmp load_setup | ||
80 | |||
81 | ok_load_setup: | ||
82 | |||
83 | # Get disk drive parameters, specifically nr of sectors/track | ||
84 | |||
85 | mov $0x00, %dl | ||
86 | mov $0x0800, %ax # AH=8 is get drive parameters | ||
87 | int $0x13 | ||
88 | mov $0x00, %ch | ||
89 | #seg cs | ||
90 | mov %cx, %cs:sectors+0 # %cs means sectors is in %cs | ||
91 | mov $INITSEG, %ax | ||
92 | mov %ax, %es | ||
93 | |||
94 | # Print some inane message | ||
95 | |||
96 | mov $0x03, %ah # read cursor pos | ||
97 | xor %bh, %bh | ||
98 | int $0x10 | ||
99 | |||
100 | mov $24, %cx | ||
101 | mov $0x0007, %bx # page 0, attribute 7 (normal) | ||
102 | #lea msg1, %bp | ||
103 | mov $msg1, %bp | ||
104 | mov $0x1301, %ax # write string, move cursor | ||
105 | int $0x10 | ||
106 | |||
107 | # ok, we've written the message, now | ||
108 | # we want to load the system (at 0x10000) | ||
109 | |||
110 | mov $SYSSEG, %ax | ||
111 | mov %ax, %es # segment of 0x010000 | ||
112 | call read_it | ||
113 | call kill_motor | ||
114 | |||
115 | # After that we check which root-device to use. If the device is | ||
116 | # defined (#= 0), nothing is done and the given device is used. | ||
117 | # Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending | ||
118 | # on the number of sectors that the BIOS reports currently. | ||
119 | |||
120 | #seg cs | ||
121 | mov %cs:root_dev+0, %ax | ||
122 | cmp $0, %ax | ||
123 | jne root_defined | ||
124 | #seg cs | ||
125 | mov %cs:sectors+0, %bx | ||
126 | mov $0x0208, %ax # /dev/ps0 - 1.2Mb | ||
127 | cmp $15, %bx | ||
128 | je root_defined | ||
129 | mov $0x021c, %ax # /dev/PS0 - 1.44Mb | ||
130 | cmp $18, %bx | ||
131 | je root_defined | ||
132 | undef_root: | ||
133 | jmp undef_root | ||
134 | root_defined: | ||
135 | #seg cs | ||
136 | mov %ax, %cs:root_dev+0 | ||
137 | |||
138 | # after that (everyting loaded), we jump to | ||
139 | # the setup-routine loaded directly after | ||
140 | # the bootblock: | ||
141 | |||
142 | ljmp $SETUPSEG, $0 | ||
143 | |||
144 | # This routine loads the system at address 0x10000, making sure | ||
145 | # no 64kB boundaries are crossed. We try to load it as fast as | ||
146 | # possible, loading whole tracks whenever we can. | ||
147 | # | ||
148 | # in: es - starting address segment (normally 0x1000) | ||
149 | # | ||
150 | sread: .word 1+ SETUPLEN # sectors read of current track | ||
151 | head: .word 0 # current head | ||
152 | track: .word 0 # current track | ||
153 | |||
154 | read_it: | ||
155 | mov %es, %ax | ||
156 | test $0x0fff, %ax | ||
157 | die: jne die # es must be at 64kB boundary | ||
158 | xor %bx, %bx # bx is starting address within segment | ||
159 | rp_read: | ||
160 | mov %es, %ax | ||
161 | cmp $ENDSEG, %ax # have we loaded all yet? | ||
162 | jb ok1_read | ||
163 | ret | ||
164 | ok1_read: | ||
165 | #seg cs | ||
166 | mov %cs:sectors+0, %ax | ||
167 | sub sread, %ax | ||
168 | mov %ax, %cx | ||
169 | shl $9, %cx | ||
170 | add %bx, %cx | ||
171 | jnc ok2_read | ||
172 | je ok2_read | ||
173 | xor %ax, %ax | ||
174 | sub %bx, %ax | ||
175 | shr $9, %ax | ||
176 | ok2_read: | ||
177 | call read_track | ||
178 | mov %ax, %cx | ||
179 | add sread, %ax | ||
180 | #seg cs | ||
181 | cmp %cs:sectors+0, %ax | ||
182 | jne ok3_read | ||
183 | mov $1, %ax | ||
184 | sub head, %ax | ||
185 | jne ok4_read | ||
186 | incw track | ||
187 | ok4_read: | ||
188 | mov %ax, head | ||
189 | xor %ax, %ax | ||
190 | ok3_read: | ||
191 | mov %ax, sread | ||
192 | shl $9, %cx | ||
193 | add %cx, %bx | ||
194 | jnc rp_read | ||
195 | mov %es, %ax | ||
196 | add $0x1000, %ax | ||
197 | mov %ax, %es | ||
198 | xor %bx, %bx | ||
199 | jmp rp_read | ||
200 | |||
201 | read_track: | ||
202 | push %ax | ||
203 | push %bx | ||
204 | push %cx | ||
205 | push %dx | ||
206 | mov track, %dx | ||
207 | mov sread, %cx | ||
208 | inc %cx | ||
209 | mov %dl, %ch | ||
210 | mov head, %dx | ||
211 | mov %dl, %dh | ||
212 | mov $0, %dl | ||
213 | and $0x0100, %dx | ||
214 | mov $2, %ah | ||
215 | int $0x13 | ||
216 | jc bad_rt | ||
217 | pop %dx | ||
218 | pop %cx | ||
219 | pop %bx | ||
220 | pop %ax | ||
221 | ret | ||
222 | bad_rt: mov $0, %ax | ||
223 | mov $0, %dx | ||
224 | int $0x13 | ||
225 | pop %dx | ||
226 | pop %cx | ||
227 | pop %bx | ||
228 | pop %ax | ||
229 | jmp read_track | ||
230 | |||
231 | #/* | ||
232 | # * This procedure turns off the floppy drive motor, so | ||
233 | # * that we enter the kernel in a known state, and | ||
234 | # * don't have to worry about it later. | ||
235 | # */ | ||
236 | kill_motor: | ||
237 | push %dx | ||
238 | mov $0x3f2, %dx | ||
239 | mov $0, %al | ||
240 | outsb | ||
241 | pop %dx | ||
242 | ret | ||
243 | |||
244 | sectors: | ||
245 | .word 0 | ||
246 | |||
247 | msg1: | ||
248 | .byte 13,10 | ||
249 | .ascii "Loading system ..." | ||
250 | .byte 13,10,13,10 | ||
251 | |||
252 | .org 508 | ||
253 | root_dev: | ||
254 | .word ROOT_DEV | ||
255 | boot_flag: | ||
256 | .word 0xAA55 | ||
257 | |||
258 | .text | ||
259 | endtext: | ||
260 | .data | ||
261 | enddata: | ||
262 | .bss | ||
263 | endbss: | ||
diff --git a/src/boot/head.s b/src/boot/head.s new file mode 100644 index 0000000..915d66a --- /dev/null +++ b/src/boot/head.s | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * linux/boot/head.s | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * head.s contains the 32-bit startup code. | ||
9 | * | ||
10 | * NOTE!!! Startup happens at absolute address 0x00000000, which is also where | ||
11 | * the page directory will exist. The startup code will be overwritten by | ||
12 | * the page directory. | ||
13 | */ | ||
14 | .text | ||
15 | .globl idt,gdt,pg_dir,tmp_floppy_area | ||
16 | pg_dir: | ||
17 | .globl startup_32 | ||
18 | startup_32: | ||
19 | movl $0x10,%eax | ||
20 | mov %ax,%ds | ||
21 | mov %ax,%es | ||
22 | mov %ax,%fs | ||
23 | mov %ax,%gs | ||
24 | lss stack_start,%esp | ||
25 | call setup_idt | ||
26 | call setup_gdt | ||
27 | movl $0x10,%eax # reload all the segment registers | ||
28 | mov %ax,%ds # after changing gdt. CS was already | ||
29 | mov %ax,%es # reloaded in 'setup_gdt' | ||
30 | mov %ax,%fs | ||
31 | mov %ax,%gs | ||
32 | lss stack_start,%esp | ||
33 | xorl %eax,%eax | ||
34 | 1: incl %eax # check that A20 really IS enabled | ||
35 | movl %eax,0x000000 # loop forever if it isn't | ||
36 | cmpl %eax,0x100000 | ||
37 | je 1b | ||
38 | |||
39 | /* | ||
40 | * NOTE! 486 should set bit 16, to check for write-protect in supervisor | ||
41 | * mode. Then it would be unnecessary with the "verify_area()"-calls. | ||
42 | * 486 users probably want to set the NE (#5) bit also, so as to use | ||
43 | * int 16 for math errors. | ||
44 | */ | ||
45 | movl %cr0,%eax # check math chip | ||
46 | andl $0x80000011,%eax # Save PG,PE,ET | ||
47 | /* "orl $0x10020,%eax" here for 486 might be good */ | ||
48 | orl $2,%eax # set MP | ||
49 | movl %eax,%cr0 | ||
50 | call check_x87 | ||
51 | jmp after_page_tables | ||
52 | |||
53 | /* | ||
54 | * We depend on ET to be correct. This checks for 287/387. | ||
55 | */ | ||
56 | check_x87: | ||
57 | fninit | ||
58 | fstsw %ax | ||
59 | cmpb $0,%al | ||
60 | je 1f /* no coprocessor: have to set bits */ | ||
61 | movl %cr0,%eax | ||
62 | xorl $6,%eax /* reset MP, set EM */ | ||
63 | movl %eax,%cr0 | ||
64 | ret | ||
65 | .align 2 | ||
66 | 1: .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ | ||
67 | ret | ||
68 | |||
69 | /* | ||
70 | * setup_idt | ||
71 | * | ||
72 | * sets up a idt with 256 entries pointing to | ||
73 | * ignore_int, interrupt gates. It then loads | ||
74 | * idt. Everything that wants to install itself | ||
75 | * in the idt-table may do so themselves. Interrupts | ||
76 | * are enabled elsewhere, when we can be relatively | ||
77 | * sure everything is ok. This routine will be over- | ||
78 | * written by the page tables. | ||
79 | */ | ||
80 | setup_idt: | ||
81 | lea ignore_int,%edx | ||
82 | movl $0x00080000,%eax | ||
83 | movw %dx,%ax /* selector = 0x0008 = cs */ | ||
84 | movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ | ||
85 | |||
86 | lea idt,%edi | ||
87 | mov $256,%ecx | ||
88 | rp_sidt: | ||
89 | movl %eax,(%edi) | ||
90 | movl %edx,4(%edi) | ||
91 | addl $8,%edi | ||
92 | dec %ecx | ||
93 | jne rp_sidt | ||
94 | lidt idt_descr | ||
95 | ret | ||
96 | |||
97 | /* | ||
98 | * setup_gdt | ||
99 | * | ||
100 | * This routines sets up a new gdt and loads it. | ||
101 | * Only two entries are currently built, the same | ||
102 | * ones that were built in init.s. The routine | ||
103 | * is VERY complicated at two whole lines, so this | ||
104 | * rather long comment is certainly needed :-). | ||
105 | * This routine will beoverwritten by the page tables. | ||
106 | */ | ||
107 | setup_gdt: | ||
108 | lgdt gdt_descr | ||
109 | ret | ||
110 | |||
111 | /* | ||
112 | * I put the kernel page tables right after the page directory, | ||
113 | * using 4 of them to span 16 Mb of physical memory. People with | ||
114 | * more than 16MB will have to expand this. | ||
115 | */ | ||
116 | .org 0x1000 | ||
117 | pg0: | ||
118 | |||
119 | .org 0x2000 | ||
120 | pg1: | ||
121 | |||
122 | .org 0x3000 | ||
123 | pg2: | ||
124 | |||
125 | .org 0x4000 | ||
126 | pg3: | ||
127 | |||
128 | .org 0x5000 | ||
129 | /* | ||
130 | * tmp_floppy_area is used by the floppy-driver when DMA cannot | ||
131 | * reach to a buffer-block. It needs to be aligned, so that it isn't | ||
132 | * on a 64kB border. | ||
133 | */ | ||
134 | tmp_floppy_area: | ||
135 | .fill 1024,1,0 | ||
136 | |||
137 | after_page_tables: | ||
138 | pushl $0 # These are the parameters to main :-) | ||
139 | pushl $0 | ||
140 | pushl $0 | ||
141 | pushl $L6 # return address for main, if it decides to. | ||
142 | pushl $main | ||
143 | jmp setup_paging | ||
144 | L6: | ||
145 | jmp L6 # main should never return here, but | ||
146 | # just in case, we know what happens. | ||
147 | |||
148 | /* This is the default interrupt "handler" :-) */ | ||
149 | int_msg: | ||
150 | .asciz "Unknown interrupt\n\r" | ||
151 | .align 2 | ||
152 | ignore_int: | ||
153 | pushl %eax | ||
154 | pushl %ecx | ||
155 | pushl %edx | ||
156 | push %ds | ||
157 | push %es | ||
158 | push %fs | ||
159 | movl $0x10,%eax | ||
160 | mov %ax,%ds | ||
161 | mov %ax,%es | ||
162 | mov %ax,%fs | ||
163 | pushl $int_msg | ||
164 | call printk | ||
165 | popl %eax | ||
166 | pop %fs | ||
167 | pop %es | ||
168 | pop %ds | ||
169 | popl %edx | ||
170 | popl %ecx | ||
171 | popl %eax | ||
172 | iret | ||
173 | |||
174 | |||
175 | /* | ||
176 | * Setup_paging | ||
177 | * | ||
178 | * This routine sets up paging by setting the page bit | ||
179 | * in cr0. The page tables are set up, identity-mapping | ||
180 | * the first 16MB. The pager assumes that no illegal | ||
181 | * addresses are produced (ie >4Mb on a 4Mb machine). | ||
182 | * | ||
183 | * NOTE! Although all physical memory should be identity | ||
184 | * mapped by this routine, only the kernel page functions | ||
185 | * use the >1Mb addresses directly. All "normal" functions | ||
186 | * use just the lower 1Mb, or the local data space, which | ||
187 | * will be mapped to some other place - mm keeps track of | ||
188 | * that. | ||
189 | * | ||
190 | * For those with more memory than 16 Mb - tough luck. I've | ||
191 | * not got it, why should you :-) The source is here. Change | ||
192 | * it. (Seriously - it shouldn't be too difficult. Mostly | ||
193 | * change some constants etc. I left it at 16Mb, as my machine | ||
194 | * even cannot be extended past that (ok, but it was cheap :-) | ||
195 | * I've tried to show which constants to change by having | ||
196 | * some kind of marker at them (search for "16Mb"), but I | ||
197 | * won't guarantee that's all :-( ) | ||
198 | */ | ||
199 | .align 2 | ||
200 | setup_paging: | ||
201 | movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ | ||
202 | xorl %eax,%eax | ||
203 | xorl %edi,%edi /* pg_dir is at 0x000 */ | ||
204 | cld;rep;stosl | ||
205 | movl $pg0+7,pg_dir /* set present bit/user r/w */ | ||
206 | movl $pg1+7,pg_dir+4 /* --------- " " --------- */ | ||
207 | movl $pg2+7,pg_dir+8 /* --------- " " --------- */ | ||
208 | movl $pg3+7,pg_dir+12 /* --------- " " --------- */ | ||
209 | movl $pg3+4092,%edi | ||
210 | movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ | ||
211 | std | ||
212 | 1: stosl /* fill pages backwards - more efficient :-) */ | ||
213 | subl $0x1000,%eax | ||
214 | jge 1b | ||
215 | cld | ||
216 | xorl %eax,%eax /* pg_dir is at 0x0000 */ | ||
217 | movl %eax,%cr3 /* cr3 - page directory start */ | ||
218 | movl %cr0,%eax | ||
219 | orl $0x80000000,%eax | ||
220 | movl %eax,%cr0 /* set paging (PG) bit */ | ||
221 | ret /* this also flushes prefetch-queue */ | ||
222 | |||
223 | .align 2 | ||
224 | .word 0 | ||
225 | idt_descr: | ||
226 | .word 256*8-1 # idt contains 256 entries | ||
227 | .long idt | ||
228 | .align 2 | ||
229 | .word 0 | ||
230 | gdt_descr: | ||
231 | .word 256*8-1 # so does gdt (not that that's any | ||
232 | .long gdt # magic number, but it works for me :^) | ||
233 | |||
234 | .align 8 | ||
235 | idt: .fill 256,8,0 # idt is uninitialized | ||
236 | |||
237 | gdt: .quad 0x0000000000000000 /* NULL descriptor */ | ||
238 | .quad 0x00c09a0000000fff /* 16Mb */ | ||
239 | .quad 0x00c0920000000fff /* 16Mb */ | ||
240 | .quad 0x0000000000000000 /* TEMPORARY - don't use */ | ||
241 | .fill 252,8,0 /* space for LDT's and TSS's etc */ | ||
diff --git a/src/boot/setup.s b/src/boot/setup.s new file mode 100644 index 0000000..b8aae75 --- /dev/null +++ b/src/boot/setup.s | |||
@@ -0,0 +1,242 @@ | |||
1 | .code16 | ||
2 | # rewrite with AT&T syntax by falcon <wuzhangjin@gmail.com> at 081012 | ||
3 | # | ||
4 | # setup.s (C) 1991 Linus Torvalds | ||
5 | # | ||
6 | # setup.s is responsible for getting the system data from the BIOS, | ||
7 | # and putting them into the appropriate places in system memory. | ||
8 | # both setup.s and system has been loaded by the bootblock. | ||
9 | # | ||
10 | # This code asks the bios for memory/disk/other parameters, and | ||
11 | # puts them in a "safe" place: 0x90000-0x901FF, ie where the | ||
12 | # boot-block used to be. It is then up to the protected mode | ||
13 | # system to read them from there before the area is overwritten | ||
14 | # for buffer-blocks. | ||
15 | # | ||
16 | |||
17 | # NOTE! These had better be the same as in bootsect.s! | ||
18 | |||
19 | .equ INITSEG, 0x9000 # we move boot here - out of the way | ||
20 | .equ SYSSEG, 0x1000 # system loaded at 0x10000 (65536). | ||
21 | .equ SETUPSEG, 0x9020 # this is the current segment | ||
22 | |||
23 | .global _start, begtext, begdata, begbss, endtext, enddata, endbss | ||
24 | .text | ||
25 | begtext: | ||
26 | .data | ||
27 | begdata: | ||
28 | .bss | ||
29 | begbss: | ||
30 | .text | ||
31 | |||
32 | ljmp $SETUPSEG, $_start | ||
33 | _start: | ||
34 | |||
35 | # ok, the read went well so we get current cursor position and save it for | ||
36 | # posterity. | ||
37 | |||
38 | mov $INITSEG, %ax # this is done in bootsect already, but... | ||
39 | mov %ax, %ds | ||
40 | mov $0x03, %ah # read cursor pos | ||
41 | xor %bh, %bh | ||
42 | int $0x10 # save it in known place, con_init fetches | ||
43 | mov %dx, %ds:0 # it from 0x90000. | ||
44 | # Get memory size (extended mem, kB) | ||
45 | |||
46 | mov $0x88, %ah | ||
47 | int $0x15 | ||
48 | mov %ax, %ds:2 | ||
49 | |||
50 | # Get video-card data: | ||
51 | |||
52 | mov $0x0f, %ah | ||
53 | int $0x10 | ||
54 | mov %bx, %ds:4 # bh = display page | ||
55 | mov %ax, %ds:6 # al = video mode, ah = window width | ||
56 | |||
57 | # check for EGA/VGA and some config parameters | ||
58 | |||
59 | mov $0x12, %ah | ||
60 | mov $0x10, %bl | ||
61 | int $0x10 | ||
62 | mov %ax, %ds:8 | ||
63 | mov %bx, %ds:10 | ||
64 | mov %cx, %ds:12 | ||
65 | |||
66 | # Get hd0 data | ||
67 | |||
68 | mov $0x0000, %ax | ||
69 | mov %ax, %ds | ||
70 | lds %ds:4*0x41, %si | ||
71 | mov $INITSEG, %ax | ||
72 | mov %ax, %es | ||
73 | mov $0x0080, %di | ||
74 | mov $0x10, %cx | ||
75 | rep | ||
76 | movsb | ||
77 | |||
78 | # Get hd1 data | ||
79 | |||
80 | mov $0x0000, %ax | ||
81 | mov %ax, %ds | ||
82 | lds %ds:4*0x46, %si | ||
83 | mov $INITSEG, %ax | ||
84 | mov %ax, %es | ||
85 | mov $0x0090, %di | ||
86 | mov $0x10, %cx | ||
87 | rep | ||
88 | movsb | ||
89 | |||
90 | # Check that there IS a hd1 :-) | ||
91 | |||
92 | mov $0x01500, %ax | ||
93 | mov $0x81, %dl | ||
94 | int $0x13 | ||
95 | jc no_disk1 | ||
96 | cmp $3, %ah | ||
97 | je is_disk1 | ||
98 | no_disk1: | ||
99 | mov $INITSEG, %ax | ||
100 | mov %ax, %es | ||
101 | mov $0x0090, %di | ||
102 | mov $0x10, %cx | ||
103 | mov $0x00, %ax | ||
104 | rep | ||
105 | stosb | ||
106 | is_disk1: | ||
107 | |||
108 | # now we want to move to protected mode ... | ||
109 | |||
110 | cli # no interrupts allowed ! | ||
111 | |||
112 | # first we move the system to it's rightful place | ||
113 | |||
114 | mov $0x0000, %ax | ||
115 | cld # 'direction'=0, movs moves forward | ||
116 | do_move: | ||
117 | mov %ax, %es # destination segment | ||
118 | add $0x1000, %ax | ||
119 | cmp $0x9000, %ax | ||
120 | jz end_move | ||
121 | mov %ax, %ds # source segment | ||
122 | sub %di, %di | ||
123 | sub %si, %si | ||
124 | mov $0x8000, %cx | ||
125 | rep | ||
126 | movsw | ||
127 | jmp do_move | ||
128 | |||
129 | # then we load the segment descriptors | ||
130 | |||
131 | end_move: | ||
132 | mov $SETUPSEG, %ax # right, forgot this at first. didn't work :-) | ||
133 | mov %ax, %ds | ||
134 | lidt idt_48 # load idt with 0,0 | ||
135 | lgdt gdt_48 # load gdt with whatever appropriate | ||
136 | |||
137 | # that was painless, now we enable A20 | ||
138 | |||
139 | #call empty_8042 # 8042 is the keyboard controller | ||
140 | #mov $0xD1, %al # command write | ||
141 | #out %al, $0x64 | ||
142 | #call empty_8042 | ||
143 | #mov $0xDF, %al # A20 on | ||
144 | #out %al, $0x60 | ||
145 | #call empty_8042 | ||
146 | inb $0x92, %al # open A20 line(Fast Gate A20). | ||
147 | orb $0b00000010, %al | ||
148 | outb %al, $0x92 | ||
149 | |||
150 | # well, that went ok, I hope. Now we have to reprogram the interrupts :-( | ||
151 | # we put them right after the intel-reserved hardware interrupts, at | ||
152 | # int 0x20-0x2F. There they won't mess up anything. Sadly IBM really | ||
153 | # messed this up with the original PC, and they haven't been able to | ||
154 | # rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, | ||
155 | # which is used for the internal hardware interrupts as well. We just | ||
156 | # have to reprogram the 8259's, and it isn't fun. | ||
157 | |||
158 | mov $0x11, %al # initialization sequence(ICW1) | ||
159 | # ICW4 needed(1),CASCADE mode,Level-triggered | ||
160 | out %al, $0x20 # send it to 8259A-1 | ||
161 | .word 0x00eb,0x00eb # jmp $+2, jmp $+2 | ||
162 | out %al, $0xA0 # and to 8259A-2 | ||
163 | .word 0x00eb,0x00eb | ||
164 | mov $0x20, %al # start of hardware int's (0x20)(ICW2) | ||
165 | out %al, $0x21 # from 0x20-0x27 | ||
166 | .word 0x00eb,0x00eb | ||
167 | mov $0x28, %al # start of hardware int's 2 (0x28) | ||
168 | out %al, $0xA1 # from 0x28-0x2F | ||
169 | .word 0x00eb,0x00eb # IR 7654 3210 | ||
170 | mov $0x04, %al # 8259-1 is master(0000 0100) --\ | ||
171 | out %al, $0x21 # | | ||
172 | .word 0x00eb,0x00eb # INT / | ||
173 | mov $0x02, %al # 8259-2 is slave( 010 --> 2) | ||
174 | out %al, $0xA1 | ||
175 | .word 0x00eb,0x00eb | ||
176 | mov $0x01, %al # 8086 mode for both | ||
177 | out %al, $0x21 | ||
178 | .word 0x00eb,0x00eb | ||
179 | out %al, $0xA1 | ||
180 | .word 0x00eb,0x00eb | ||
181 | mov $0xFF, %al # mask off all interrupts for now | ||
182 | out %al, $0x21 | ||
183 | .word 0x00eb,0x00eb | ||
184 | out %al, $0xA1 | ||
185 | |||
186 | # well, that certainly wasn't fun :-(. Hopefully it works, and we don't | ||
187 | # need no steenking BIOS anyway (except for the initial loading :-). | ||
188 | # The BIOS-routine wants lots of unnecessary data, and it's less | ||
189 | # "interesting" anyway. This is how REAL programmers do it. | ||
190 | # | ||
191 | # Well, now's the time to actually move into protected mode. To make | ||
192 | # things as simple as possible, we do no register set-up or anything, | ||
193 | # we let the gnu-compiled 32-bit programs do that. We just jump to | ||
194 | # absolute address 0x00000, in 32-bit protected mode. | ||
195 | #mov $0x0001, %ax # protected mode (PE) bit | ||
196 | #lmsw %ax # This is it! | ||
197 | mov %cr0, %eax # get machine status(cr0|MSW) | ||
198 | bts $0, %eax # turn on the PE-bit | ||
199 | mov %eax, %cr0 # protection enabled | ||
200 | |||
201 | # segment-descriptor (INDEX:TI:RPL) | ||
202 | .equ sel_cs0, 0x0008 # select for code segment 0 ( 001:0 :00) | ||
203 | ljmp $sel_cs0, $0 # jmp offset 0 of code segment 0 in gdt | ||
204 | |||
205 | # This routine checks that the keyboard command queue is empty | ||
206 | # No timeout is used - if this hangs there is something wrong with | ||
207 | # the machine, and we probably couldn't proceed anyway. | ||
208 | empty_8042: | ||
209 | .word 0x00eb,0x00eb | ||
210 | in $0x64, %al # 8042 status port | ||
211 | test $2, %al # is input buffer full? | ||
212 | jnz empty_8042 # yes - loop | ||
213 | ret | ||
214 | |||
215 | gdt: | ||
216 | .word 0,0,0,0 # dummy | ||
217 | |||
218 | .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb) | ||
219 | .word 0x0000 # base address=0 | ||
220 | .word 0x9A00 # code read/exec | ||
221 | .word 0x00C0 # granularity=4096, 386 | ||
222 | |||
223 | .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb) | ||
224 | .word 0x0000 # base address=0 | ||
225 | .word 0x9200 # data read/write | ||
226 | .word 0x00C0 # granularity=4096, 386 | ||
227 | |||
228 | idt_48: | ||
229 | .word 0 # idt limit=0 | ||
230 | .word 0,0 # idt base=0L | ||
231 | |||
232 | gdt_48: | ||
233 | .word 0x800 # gdt limit=2048, 256 GDT entries | ||
234 | .word 512+gdt, 0x9 # gdt base = 0X9xxxx, | ||
235 | # 512+gdt is the real gdt after setup is moved to 0x9020 * 0x10 | ||
236 | |||
237 | .text | ||
238 | endtext: | ||
239 | .data | ||
240 | enddata: | ||
241 | .bss | ||
242 | endbss: | ||
diff --git a/src/fs/Makefile b/src/fs/Makefile new file mode 100644 index 0000000..dc85240 --- /dev/null +++ b/src/fs/Makefile | |||
@@ -0,0 +1,98 @@ | |||
1 | include ../Makefile.header | ||
2 | |||
3 | LDFLAGS += -r | ||
4 | CFLAGS += -I../include | ||
5 | CPP += -I../include | ||
6 | |||
7 | .c.s: | ||
8 | @$(CC) $(CFLAGS) \ | ||
9 | -S -o $*.s $< | ||
10 | .c.o: | ||
11 | @$(CC) $(CFLAGS) \ | ||
12 | -c -o $*.o $< | ||
13 | .s.o: | ||
14 | $(AS) -o $*.o $< | ||
15 | |||
16 | OBJS= open.o read_write.o inode.o file_table.o buffer.o super.o \ | ||
17 | block_dev.o char_dev.o file_dev.o stat.o exec.o pipe.o namei.o \ | ||
18 | bitmap.o fcntl.o ioctl.o truncate.o | ||
19 | |||
20 | fs.o: $(OBJS) | ||
21 | @$(LD) $(LDFLAGS) -o fs.o $(OBJS) | ||
22 | |||
23 | clean: | ||
24 | @rm -f core *.o *.a tmp_make | ||
25 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
26 | |||
27 | dep: | ||
28 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
29 | @(for i in *.c;do $(CPP) -M $$i;done) >> tmp_make | ||
30 | @cp tmp_make Makefile | ||
31 | |||
32 | ### Dependencies: | ||
33 | bitmap.o: bitmap.c ../include/string.h ../include/linux/sched.h \ | ||
34 | ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ | ||
35 | ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h | ||
36 | block_dev.o: block_dev.c ../include/errno.h ../include/linux/sched.h \ | ||
37 | ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ | ||
38 | ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ | ||
39 | ../include/asm/segment.h ../include/asm/system.h | ||
40 | buffer.o: buffer.c ../include/stdarg.h ../include/linux/config.h \ | ||
41 | ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ | ||
42 | ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ | ||
43 | ../include/linux/kernel.h ../include/asm/system.h ../include/asm/io.h | ||
44 | char_dev.o: char_dev.c ../include/errno.h ../include/sys/types.h \ | ||
45 | ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ | ||
46 | ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ | ||
47 | ../include/asm/segment.h ../include/asm/io.h | ||
48 | exec.o: exec.c ../include/errno.h ../include/string.h \ | ||
49 | ../include/sys/stat.h ../include/sys/types.h ../include/a.out.h \ | ||
50 | ../include/linux/fs.h ../include/linux/sched.h ../include/linux/head.h \ | ||
51 | ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ | ||
52 | ../include/asm/segment.h | ||
53 | fcntl.o: fcntl.c ../include/string.h ../include/errno.h \ | ||
54 | ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ | ||
55 | ../include/sys/types.h ../include/linux/mm.h ../include/signal.h \ | ||
56 | ../include/linux/kernel.h ../include/asm/segment.h ../include/fcntl.h \ | ||
57 | ../include/sys/stat.h | ||
58 | file_dev.o: file_dev.c ../include/errno.h ../include/fcntl.h \ | ||
59 | ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ | ||
60 | ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ | ||
61 | ../include/linux/kernel.h ../include/asm/segment.h | ||
62 | file_table.o: file_table.c ../include/linux/fs.h ../include/sys/types.h | ||
63 | inode.o: inode.c ../include/string.h ../include/sys/stat.h \ | ||
64 | ../include/sys/types.h ../include/linux/sched.h ../include/linux/head.h \ | ||
65 | ../include/linux/fs.h ../include/linux/mm.h ../include/signal.h \ | ||
66 | ../include/linux/kernel.h ../include/asm/system.h | ||
67 | ioctl.o: ioctl.c ../include/string.h ../include/errno.h \ | ||
68 | ../include/sys/stat.h ../include/sys/types.h ../include/linux/sched.h \ | ||
69 | ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ | ||
70 | ../include/signal.h | ||
71 | namei.o: namei.c ../include/linux/sched.h ../include/linux/head.h \ | ||
72 | ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ | ||
73 | ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h \ | ||
74 | ../include/string.h ../include/fcntl.h ../include/errno.h \ | ||
75 | ../include/const.h ../include/sys/stat.h | ||
76 | open.o: open.c ../include/string.h ../include/errno.h ../include/fcntl.h \ | ||
77 | ../include/sys/types.h ../include/utime.h ../include/sys/stat.h \ | ||
78 | ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ | ||
79 | ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ | ||
80 | ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h | ||
81 | pipe.o: pipe.c ../include/signal.h ../include/sys/types.h \ | ||
82 | ../include/linux/sched.h ../include/linux/head.h ../include/linux/fs.h \ | ||
83 | ../include/linux/mm.h ../include/asm/segment.h | ||
84 | read_write.o: read_write.c ../include/sys/stat.h ../include/sys/types.h \ | ||
85 | ../include/errno.h ../include/linux/kernel.h ../include/linux/sched.h \ | ||
86 | ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ | ||
87 | ../include/signal.h ../include/asm/segment.h | ||
88 | stat.o: stat.c ../include/errno.h ../include/sys/stat.h \ | ||
89 | ../include/sys/types.h ../include/linux/fs.h ../include/linux/sched.h \ | ||
90 | ../include/linux/head.h ../include/linux/mm.h ../include/signal.h \ | ||
91 | ../include/linux/kernel.h ../include/asm/segment.h | ||
92 | super.o: super.c ../include/linux/config.h ../include/linux/sched.h \ | ||
93 | ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ | ||
94 | ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ | ||
95 | ../include/asm/system.h ../include/errno.h ../include/sys/stat.h | ||
96 | truncate.o: truncate.c ../include/linux/sched.h ../include/linux/head.h \ | ||
97 | ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ | ||
98 | ../include/signal.h ../include/sys/stat.h | ||
diff --git a/src/fs/bitmap.c b/src/fs/bitmap.c new file mode 100644 index 0000000..fb0741d --- /dev/null +++ b/src/fs/bitmap.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * linux/fs/bitmap.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* bitmap.c contains the code that handles the inode and block bitmaps */ | ||
8 | #include <string.h> | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/kernel.h> | ||
12 | |||
13 | #define clear_block(addr) \ | ||
14 | __asm__ __volatile__ ("cld\n\t" \ | ||
15 | "rep\n\t" \ | ||
16 | "stosl" \ | ||
17 | ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr))) | ||
18 | |||
19 | #define set_bit(nr,addr) ({\ | ||
20 | register int res ; \ | ||
21 | __asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \ | ||
22 | "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ | ||
23 | res;}) | ||
24 | |||
25 | #define clear_bit(nr,addr) ({\ | ||
26 | register int res ; \ | ||
27 | __asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \ | ||
28 | "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \ | ||
29 | res;}) | ||
30 | |||
31 | #define find_first_zero(addr) ({ \ | ||
32 | int __res; \ | ||
33 | __asm__ __volatile__ ("cld\n" \ | ||
34 | "1:\tlodsl\n\t" \ | ||
35 | "notl %%eax\n\t" \ | ||
36 | "bsfl %%eax,%%edx\n\t" \ | ||
37 | "je 2f\n\t" \ | ||
38 | "addl %%edx,%%ecx\n\t" \ | ||
39 | "jmp 3f\n" \ | ||
40 | "2:\taddl $32,%%ecx\n\t" \ | ||
41 | "cmpl $8192,%%ecx\n\t" \ | ||
42 | "jl 1b\n" \ | ||
43 | "3:" \ | ||
44 | :"=c" (__res):"c" (0),"S" (addr)); \ | ||
45 | __res;}) | ||
46 | |||
47 | void free_block(int dev, int block) | ||
48 | { | ||
49 | struct super_block * sb; | ||
50 | struct buffer_head * bh; | ||
51 | |||
52 | if (!(sb = get_super(dev))) | ||
53 | panic("trying to free block on nonexistent device"); | ||
54 | if (block < sb->s_firstdatazone || block >= sb->s_nzones) | ||
55 | panic("trying to free block not in datazone"); | ||
56 | bh = get_hash_table(dev,block); | ||
57 | if (bh) { | ||
58 | if (bh->b_count != 1) { | ||
59 | printk("trying to free block (%04x:%d), count=%d\n", | ||
60 | dev,block,bh->b_count); | ||
61 | return; | ||
62 | } | ||
63 | bh->b_dirt=0; | ||
64 | bh->b_uptodate=0; | ||
65 | brelse(bh); | ||
66 | } | ||
67 | block -= sb->s_firstdatazone - 1 ; | ||
68 | if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) { | ||
69 | printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1); | ||
70 | panic("free_block: bit already cleared"); | ||
71 | } | ||
72 | sb->s_zmap[block/8192]->b_dirt = 1; | ||
73 | } | ||
74 | |||
75 | int new_block(int dev) | ||
76 | { | ||
77 | struct buffer_head * bh; | ||
78 | struct super_block * sb; | ||
79 | int i,j; | ||
80 | |||
81 | if (!(sb = get_super(dev))) | ||
82 | panic("trying to get new block from nonexistant device"); | ||
83 | j = 8192; | ||
84 | for (i=0 ; i<8 ; i++) | ||
85 | if ((bh=sb->s_zmap[i])) | ||
86 | if ((j=find_first_zero(bh->b_data))<8192) | ||
87 | break; | ||
88 | if (i>=8 || !bh || j>=8192) | ||
89 | return 0; | ||
90 | if (set_bit(j,bh->b_data)) | ||
91 | panic("new_block: bit already set"); | ||
92 | bh->b_dirt = 1; | ||
93 | j += i*8192 + sb->s_firstdatazone-1; | ||
94 | if (j >= sb->s_nzones) | ||
95 | return 0; | ||
96 | if (!(bh=getblk(dev,j))) | ||
97 | panic("new_block: cannot get block"); | ||
98 | if (bh->b_count != 1) | ||
99 | panic("new block: count is != 1"); | ||
100 | clear_block(bh->b_data); | ||
101 | bh->b_uptodate = 1; | ||
102 | bh->b_dirt = 1; | ||
103 | brelse(bh); | ||
104 | return j; | ||
105 | } | ||
106 | |||
107 | void free_inode(struct m_inode * inode) | ||
108 | { | ||
109 | struct super_block * sb; | ||
110 | struct buffer_head * bh; | ||
111 | |||
112 | if (!inode) | ||
113 | return; | ||
114 | if (!inode->i_dev) { | ||
115 | memset(inode,0,sizeof(*inode)); | ||
116 | return; | ||
117 | } | ||
118 | if (inode->i_count>1) { | ||
119 | printk("trying to free inode with count=%d\n",inode->i_count); | ||
120 | panic("free_inode"); | ||
121 | } | ||
122 | if (inode->i_nlinks) | ||
123 | panic("trying to free inode with links"); | ||
124 | if (!(sb = get_super(inode->i_dev))) | ||
125 | panic("trying to free inode on nonexistent device"); | ||
126 | if (inode->i_num < 1 || inode->i_num > sb->s_ninodes) | ||
127 | panic("trying to free inode 0 or nonexistant inode"); | ||
128 | if (!(bh=sb->s_imap[inode->i_num>>13])) | ||
129 | panic("nonexistent imap in superblock"); | ||
130 | if (clear_bit(inode->i_num&8191,bh->b_data)) | ||
131 | printk("free_inode: bit already cleared.\n\r"); | ||
132 | bh->b_dirt = 1; | ||
133 | memset(inode,0,sizeof(*inode)); | ||
134 | } | ||
135 | |||
136 | struct m_inode * new_inode(int dev) | ||
137 | { | ||
138 | struct m_inode * inode; | ||
139 | struct super_block * sb; | ||
140 | struct buffer_head * bh; | ||
141 | int i,j; | ||
142 | |||
143 | if (!(inode=get_empty_inode())) | ||
144 | return NULL; | ||
145 | if (!(sb = get_super(dev))) | ||
146 | panic("new_inode with unknown device"); | ||
147 | j = 8192; | ||
148 | for (i=0 ; i<8 ; i++) | ||
149 | if ((bh=sb->s_imap[i])) | ||
150 | if ((j=find_first_zero(bh->b_data))<8192) | ||
151 | break; | ||
152 | if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) { | ||
153 | iput(inode); | ||
154 | return NULL; | ||
155 | } | ||
156 | if (set_bit(j,bh->b_data)) | ||
157 | panic("new_inode: bit already set"); | ||
158 | bh->b_dirt = 1; | ||
159 | inode->i_count=1; | ||
160 | inode->i_nlinks=1; | ||
161 | inode->i_dev=dev; | ||
162 | inode->i_uid=current->euid; | ||
163 | inode->i_gid=current->egid; | ||
164 | inode->i_dirt=1; | ||
165 | inode->i_num = j + i*8192; | ||
166 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
167 | return inode; | ||
168 | } | ||
diff --git a/src/fs/block_dev.c b/src/fs/block_dev.c new file mode 100644 index 0000000..a50ae3f --- /dev/null +++ b/src/fs/block_dev.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * linux/fs/block_dev.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | |||
9 | #include <linux/sched.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <asm/segment.h> | ||
12 | #include <asm/system.h> | ||
13 | |||
14 | int block_write(int dev, long * pos, char * buf, int count) | ||
15 | { | ||
16 | int block = *pos >> BLOCK_SIZE_BITS; | ||
17 | int offset = *pos & (BLOCK_SIZE-1); | ||
18 | int chars; | ||
19 | int written = 0; | ||
20 | struct buffer_head * bh; | ||
21 | register char * p; | ||
22 | |||
23 | while (count>0) { | ||
24 | chars = BLOCK_SIZE - offset; | ||
25 | if (chars > count) | ||
26 | chars=count; | ||
27 | if (chars == BLOCK_SIZE) | ||
28 | bh = getblk(dev,block); | ||
29 | else | ||
30 | bh = breada(dev,block,block+1,block+2,-1); | ||
31 | block++; | ||
32 | if (!bh) | ||
33 | return written?written:-EIO; | ||
34 | p = offset + bh->b_data; | ||
35 | offset = 0; | ||
36 | *pos += chars; | ||
37 | written += chars; | ||
38 | count -= chars; | ||
39 | while (chars-->0) | ||
40 | *(p++) = get_fs_byte(buf++); | ||
41 | bh->b_dirt = 1; | ||
42 | brelse(bh); | ||
43 | } | ||
44 | return written; | ||
45 | } | ||
46 | |||
47 | int block_read(int dev, unsigned long * pos, char * buf, int count) | ||
48 | { | ||
49 | int block = *pos >> BLOCK_SIZE_BITS; | ||
50 | int offset = *pos & (BLOCK_SIZE-1); | ||
51 | int chars; | ||
52 | int read = 0; | ||
53 | struct buffer_head * bh; | ||
54 | register char * p; | ||
55 | |||
56 | while (count>0) { | ||
57 | chars = BLOCK_SIZE-offset; | ||
58 | if (chars > count) | ||
59 | chars = count; | ||
60 | if (!(bh = breada(dev,block,block+1,block+2,-1))) | ||
61 | return read?read:-EIO; | ||
62 | block++; | ||
63 | p = offset + bh->b_data; | ||
64 | offset = 0; | ||
65 | *pos += chars; | ||
66 | read += chars; | ||
67 | count -= chars; | ||
68 | while (chars-->0) | ||
69 | put_fs_byte(*(p++),buf++); | ||
70 | brelse(bh); | ||
71 | } | ||
72 | return read; | ||
73 | } | ||
diff --git a/src/fs/buffer.c b/src/fs/buffer.c new file mode 100644 index 0000000..89918e8 --- /dev/null +++ b/src/fs/buffer.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * linux/fs/buffer.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 'buffer.c' implements the buffer-cache functions. Race-conditions have | ||
9 | * been avoided by NEVER letting a interrupt change a buffer (except for the | ||
10 | * data, of course), but instead letting the caller do it. NOTE! As interrupts | ||
11 | * can wake up a caller, some cli-sti sequences are needed to check for | ||
12 | * sleep-on-calls. These should be extremely quick, though (I hope). | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * NOTE! There is one discordant note here: checking floppies for | ||
17 | * disk change. This is where it fits best, I think, as it should | ||
18 | * invalidate changed floppy-disk-caches. | ||
19 | */ | ||
20 | |||
21 | #include <stdarg.h> | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <asm/system.h> | ||
27 | #include <asm/io.h> | ||
28 | |||
29 | extern int end; | ||
30 | extern void put_super(int); | ||
31 | extern void invalidate_inodes(int); | ||
32 | |||
33 | struct buffer_head * start_buffer = (struct buffer_head *) &end; | ||
34 | struct buffer_head * hash_table[NR_HASH]; | ||
35 | static struct buffer_head * free_list; | ||
36 | static struct task_struct * buffer_wait = NULL; | ||
37 | int NR_BUFFERS = 0; | ||
38 | |||
39 | static inline void wait_on_buffer(struct buffer_head * bh) | ||
40 | { | ||
41 | cli(); | ||
42 | while (bh->b_lock) | ||
43 | sleep_on(&bh->b_wait); | ||
44 | sti(); | ||
45 | } | ||
46 | |||
47 | int sys_sync(void) | ||
48 | { | ||
49 | int i; | ||
50 | struct buffer_head * bh; | ||
51 | |||
52 | sync_inodes(); /* write out inodes into buffers */ | ||
53 | bh = start_buffer; | ||
54 | for (i=0 ; i<NR_BUFFERS ; i++,bh++) { | ||
55 | wait_on_buffer(bh); | ||
56 | if (bh->b_dirt) | ||
57 | ll_rw_block(WRITE,bh); | ||
58 | } | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | int sync_dev(int dev) | ||
63 | { | ||
64 | int i; | ||
65 | struct buffer_head * bh; | ||
66 | |||
67 | bh = start_buffer; | ||
68 | for (i=0 ; i<NR_BUFFERS ; i++,bh++) { | ||
69 | if (bh->b_dev != dev) | ||
70 | continue; | ||
71 | wait_on_buffer(bh); | ||
72 | if (bh->b_dev == dev && bh->b_dirt) | ||
73 | ll_rw_block(WRITE,bh); | ||
74 | } | ||
75 | sync_inodes(); | ||
76 | bh = start_buffer; | ||
77 | for (i=0 ; i<NR_BUFFERS ; i++,bh++) { | ||
78 | if (bh->b_dev != dev) | ||
79 | continue; | ||
80 | wait_on_buffer(bh); | ||
81 | if (bh->b_dev == dev && bh->b_dirt) | ||
82 | ll_rw_block(WRITE,bh); | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static void inline invalidate_buffers(int dev) | ||
88 | { | ||
89 | int i; | ||
90 | struct buffer_head * bh; | ||
91 | |||
92 | bh = start_buffer; | ||
93 | for (i=0 ; i<NR_BUFFERS ; i++,bh++) { | ||
94 | if (bh->b_dev != dev) | ||
95 | continue; | ||
96 | wait_on_buffer(bh); | ||
97 | if (bh->b_dev == dev) | ||
98 | bh->b_uptodate = bh->b_dirt = 0; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * This routine checks whether a floppy has been changed, and | ||
104 | * invalidates all buffer-cache-entries in that case. This | ||
105 | * is a relatively slow routine, so we have to try to minimize using | ||
106 | * it. Thus it is called only upon a 'mount' or 'open'. This | ||
107 | * is the best way of combining speed and utility, I think. | ||
108 | * People changing diskettes in the middle of an operation deserve | ||
109 | * to loose :-) | ||
110 | * | ||
111 | * NOTE! Although currently this is only for floppies, the idea is | ||
112 | * that any additional removable block-device will use this routine, | ||
113 | * and that mount/open needn't know that floppies/whatever are | ||
114 | * special. | ||
115 | */ | ||
116 | void check_disk_change(int dev) | ||
117 | { | ||
118 | int i; | ||
119 | |||
120 | if (MAJOR(dev) != 2) | ||
121 | return; | ||
122 | if (!floppy_change(dev & 0x03)) | ||
123 | return; | ||
124 | for (i=0 ; i<NR_SUPER ; i++) | ||
125 | if (super_block[i].s_dev == dev) | ||
126 | put_super(super_block[i].s_dev); | ||
127 | invalidate_inodes(dev); | ||
128 | invalidate_buffers(dev); | ||
129 | } | ||
130 | |||
131 | #define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH) | ||
132 | #define hash(dev,block) hash_table[_hashfn(dev,block)] | ||
133 | |||
134 | static inline void remove_from_queues(struct buffer_head * bh) | ||
135 | { | ||
136 | /* remove from hash-queue */ | ||
137 | if (bh->b_next) | ||
138 | bh->b_next->b_prev = bh->b_prev; | ||
139 | if (bh->b_prev) | ||
140 | bh->b_prev->b_next = bh->b_next; | ||
141 | if (hash(bh->b_dev,bh->b_blocknr) == bh) | ||
142 | hash(bh->b_dev,bh->b_blocknr) = bh->b_next; | ||
143 | /* remove from free list */ | ||
144 | if (!(bh->b_prev_free) || !(bh->b_next_free)) | ||
145 | panic("Free block list corrupted"); | ||
146 | bh->b_prev_free->b_next_free = bh->b_next_free; | ||
147 | bh->b_next_free->b_prev_free = bh->b_prev_free; | ||
148 | if (free_list == bh) | ||
149 | free_list = bh->b_next_free; | ||
150 | } | ||
151 | |||
152 | static inline void insert_into_queues(struct buffer_head * bh) | ||
153 | { | ||
154 | /* put at end of free list */ | ||
155 | bh->b_next_free = free_list; | ||
156 | bh->b_prev_free = free_list->b_prev_free; | ||
157 | free_list->b_prev_free->b_next_free = bh; | ||
158 | free_list->b_prev_free = bh; | ||
159 | /* put the buffer in new hash-queue if it has a device */ | ||
160 | bh->b_prev = NULL; | ||
161 | bh->b_next = NULL; | ||
162 | if (!bh->b_dev) | ||
163 | return; | ||
164 | bh->b_next = hash(bh->b_dev,bh->b_blocknr); | ||
165 | hash(bh->b_dev,bh->b_blocknr) = bh; | ||
166 | bh->b_next->b_prev = bh; | ||
167 | } | ||
168 | |||
169 | static struct buffer_head * find_buffer(int dev, int block) | ||
170 | { | ||
171 | struct buffer_head * tmp; | ||
172 | |||
173 | for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) | ||
174 | if (tmp->b_dev==dev && tmp->b_blocknr==block) | ||
175 | return tmp; | ||
176 | return NULL; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * Why like this, I hear you say... The reason is race-conditions. | ||
181 | * As we don't lock buffers (unless we are readint them, that is), | ||
182 | * something might happen to it while we sleep (ie a read-error | ||
183 | * will force it bad). This shouldn't really happen currently, but | ||
184 | * the code is ready. | ||
185 | */ | ||
186 | struct buffer_head * get_hash_table(int dev, int block) | ||
187 | { | ||
188 | struct buffer_head * bh; | ||
189 | |||
190 | for (;;) { | ||
191 | if (!(bh=find_buffer(dev,block))) | ||
192 | return NULL; | ||
193 | bh->b_count++; | ||
194 | wait_on_buffer(bh); | ||
195 | if (bh->b_dev == dev && bh->b_blocknr == block) | ||
196 | return bh; | ||
197 | bh->b_count--; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Ok, this is getblk, and it isn't very clear, again to hinder | ||
203 | * race-conditions. Most of the code is seldom used, (ie repeating), | ||
204 | * so it should be much more efficient than it looks. | ||
205 | * | ||
206 | * The algoritm is changed: hopefully better, and an elusive bug removed. | ||
207 | */ | ||
208 | #define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) | ||
209 | struct buffer_head * getblk(int dev,int block) | ||
210 | { | ||
211 | struct buffer_head * tmp, * bh; | ||
212 | |||
213 | repeat: | ||
214 | if ((bh = get_hash_table(dev,block))) | ||
215 | return bh; | ||
216 | tmp = free_list; | ||
217 | do { | ||
218 | if (tmp->b_count) | ||
219 | continue; | ||
220 | if (!bh || BADNESS(tmp)<BADNESS(bh)) { | ||
221 | bh = tmp; | ||
222 | if (!BADNESS(tmp)) | ||
223 | break; | ||
224 | } | ||
225 | /* and repeat until we find something good */ | ||
226 | } while ((tmp = tmp->b_next_free) != free_list); | ||
227 | if (!bh) { | ||
228 | sleep_on(&buffer_wait); | ||
229 | goto repeat; | ||
230 | } | ||
231 | wait_on_buffer(bh); | ||
232 | if (bh->b_count) | ||
233 | goto repeat; | ||
234 | while (bh->b_dirt) { | ||
235 | sync_dev(bh->b_dev); | ||
236 | wait_on_buffer(bh); | ||
237 | if (bh->b_count) | ||
238 | goto repeat; | ||
239 | } | ||
240 | /* NOTE!! While we slept waiting for this block, somebody else might */ | ||
241 | /* already have added "this" block to the cache. check it */ | ||
242 | if (find_buffer(dev,block)) | ||
243 | goto repeat; | ||
244 | /* OK, FINALLY we know that this buffer is the only one of it's kind, */ | ||
245 | /* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ | ||
246 | bh->b_count=1; | ||
247 | bh->b_dirt=0; | ||
248 | bh->b_uptodate=0; | ||
249 | remove_from_queues(bh); | ||
250 | bh->b_dev=dev; | ||
251 | bh->b_blocknr=block; | ||
252 | insert_into_queues(bh); | ||
253 | return bh; | ||
254 | } | ||
255 | |||
256 | void brelse(struct buffer_head * buf) | ||
257 | { | ||
258 | if (!buf) | ||
259 | return; | ||
260 | wait_on_buffer(buf); | ||
261 | if (!(buf->b_count--)) | ||
262 | panic("Trying to free free buffer"); | ||
263 | wake_up(&buffer_wait); | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * bread() reads a specified block and returns the buffer that contains | ||
268 | * it. It returns NULL if the block was unreadable. | ||
269 | */ | ||
270 | struct buffer_head * bread(int dev,int block) | ||
271 | { | ||
272 | struct buffer_head * bh; | ||
273 | |||
274 | if (!(bh=getblk(dev,block))) | ||
275 | panic("bread: getblk returned NULL\n"); | ||
276 | if (bh->b_uptodate) | ||
277 | return bh; | ||
278 | ll_rw_block(READ,bh); | ||
279 | wait_on_buffer(bh); | ||
280 | if (bh->b_uptodate) | ||
281 | return bh; | ||
282 | brelse(bh); | ||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | #define COPYBLK(from,to) \ | ||
287 | __asm__("cld\n\t" \ | ||
288 | "rep\n\t" \ | ||
289 | "movsl\n\t" \ | ||
290 | ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \ | ||
291 | ) | ||
292 | |||
293 | /* | ||
294 | * bread_page reads four buffers into memory at the desired address. It's | ||
295 | * a function of its own, as there is some speed to be got by reading them | ||
296 | * all at the same time, not waiting for one to be read, and then another | ||
297 | * etc. | ||
298 | */ | ||
299 | void bread_page(unsigned long address,int dev,int b[4]) | ||
300 | { | ||
301 | struct buffer_head * bh[4]; | ||
302 | int i; | ||
303 | |||
304 | for (i=0 ; i<4 ; i++) | ||
305 | if (b[i]) { | ||
306 | if ((bh[i] = getblk(dev,b[i]))) | ||
307 | if (!bh[i]->b_uptodate) | ||
308 | ll_rw_block(READ,bh[i]); | ||
309 | } else | ||
310 | bh[i] = NULL; | ||
311 | for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) | ||
312 | if (bh[i]) { | ||
313 | wait_on_buffer(bh[i]); | ||
314 | if (bh[i]->b_uptodate) | ||
315 | COPYBLK((unsigned long) bh[i]->b_data,address); | ||
316 | brelse(bh[i]); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * Ok, breada can be used as bread, but additionally to mark other | ||
322 | * blocks for reading as well. End the argument list with a negative | ||
323 | * number. | ||
324 | */ | ||
325 | struct buffer_head * breada(int dev,int first, ...) | ||
326 | { | ||
327 | va_list args; | ||
328 | struct buffer_head * bh, *tmp; | ||
329 | |||
330 | va_start(args,first); | ||
331 | if (!(bh=getblk(dev,first))) | ||
332 | panic("bread: getblk returned NULL\n"); | ||
333 | if (!bh->b_uptodate) | ||
334 | ll_rw_block(READ,bh); | ||
335 | while ((first=va_arg(args,int))>=0) { | ||
336 | tmp=getblk(dev,first); | ||
337 | if (tmp) { | ||
338 | if (!tmp->b_uptodate) | ||
339 | ll_rw_block(READA,bh); | ||
340 | tmp->b_count--; | ||
341 | } | ||
342 | } | ||
343 | va_end(args); | ||
344 | wait_on_buffer(bh); | ||
345 | if (bh->b_uptodate) | ||
346 | return bh; | ||
347 | brelse(bh); | ||
348 | return (NULL); | ||
349 | } | ||
350 | |||
351 | void buffer_init(long buffer_end) | ||
352 | { | ||
353 | struct buffer_head * h = start_buffer; | ||
354 | void * b; | ||
355 | int i; | ||
356 | |||
357 | if (buffer_end == 1<<20) | ||
358 | b = (void *) (640*1024); | ||
359 | else | ||
360 | b = (void *) buffer_end; | ||
361 | while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) { | ||
362 | h->b_dev = 0; | ||
363 | h->b_dirt = 0; | ||
364 | h->b_count = 0; | ||
365 | h->b_lock = 0; | ||
366 | h->b_uptodate = 0; | ||
367 | h->b_wait = NULL; | ||
368 | h->b_next = NULL; | ||
369 | h->b_prev = NULL; | ||
370 | h->b_data = (char *) b; | ||
371 | h->b_prev_free = h-1; | ||
372 | h->b_next_free = h+1; | ||
373 | h++; | ||
374 | NR_BUFFERS++; | ||
375 | if (b == (void *) 0x100000) | ||
376 | b = (void *) 0xA0000; | ||
377 | } | ||
378 | h--; | ||
379 | free_list = start_buffer; | ||
380 | free_list->b_prev_free = h; | ||
381 | h->b_next_free = free_list; | ||
382 | for (i=0;i<NR_HASH;i++) | ||
383 | hash_table[i]=NULL; | ||
384 | } | ||
diff --git a/src/fs/char_dev.c b/src/fs/char_dev.c new file mode 100644 index 0000000..6932e1e --- /dev/null +++ b/src/fs/char_dev.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * linux/fs/char_dev.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | #include <sys/types.h> | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/kernel.h> | ||
12 | |||
13 | #include <asm/segment.h> | ||
14 | #include <asm/io.h> | ||
15 | |||
16 | extern int tty_read(unsigned minor,char * buf,int count); | ||
17 | extern int tty_write(unsigned minor,char * buf,int count); | ||
18 | |||
19 | typedef int (*crw_ptr)(int rw,unsigned minor,char * buf,int count,off_t * pos); | ||
20 | |||
21 | static int rw_ttyx(int rw,unsigned minor,char * buf,int count,off_t * pos) | ||
22 | { | ||
23 | return ((rw==READ)?tty_read(minor,buf,count): | ||
24 | tty_write(minor,buf,count)); | ||
25 | } | ||
26 | |||
27 | static int rw_tty(int rw,unsigned minor,char * buf,int count, off_t * pos) | ||
28 | { | ||
29 | if (current->tty<0) | ||
30 | return -EPERM; | ||
31 | return rw_ttyx(rw,current->tty,buf,count,pos); | ||
32 | } | ||
33 | |||
34 | static int rw_ram(int rw,char * buf, int count, off_t *pos) | ||
35 | { | ||
36 | return -EIO; | ||
37 | } | ||
38 | |||
39 | static int rw_mem(int rw,char * buf, int count, off_t * pos) | ||
40 | { | ||
41 | return -EIO; | ||
42 | } | ||
43 | |||
44 | static int rw_kmem(int rw,char * buf, int count, off_t * pos) | ||
45 | { | ||
46 | return -EIO; | ||
47 | } | ||
48 | |||
49 | static int rw_port(int rw,char * buf, int count, off_t * pos) | ||
50 | { | ||
51 | int i=*pos; | ||
52 | |||
53 | while (count-->0 && i<65536) { | ||
54 | if (rw==READ) | ||
55 | put_fs_byte(inb(i),buf++); | ||
56 | else | ||
57 | outb(get_fs_byte(buf++),i); | ||
58 | i++; | ||
59 | } | ||
60 | i -= *pos; | ||
61 | *pos += i; | ||
62 | return i; | ||
63 | } | ||
64 | |||
65 | static int rw_memory(int rw, unsigned minor, char * buf, int count, off_t * pos) | ||
66 | { | ||
67 | switch(minor) { | ||
68 | case 0: | ||
69 | return rw_ram(rw,buf,count,pos); | ||
70 | case 1: | ||
71 | return rw_mem(rw,buf,count,pos); | ||
72 | case 2: | ||
73 | return rw_kmem(rw,buf,count,pos); | ||
74 | case 3: | ||
75 | return (rw==READ)?0:count; /* rw_null */ | ||
76 | case 4: | ||
77 | return rw_port(rw,buf,count,pos); | ||
78 | default: | ||
79 | return -EIO; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | #define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr))) | ||
84 | |||
85 | static crw_ptr crw_table[]={ | ||
86 | NULL, /* nodev */ | ||
87 | rw_memory, /* /dev/mem etc */ | ||
88 | NULL, /* /dev/fd */ | ||
89 | NULL, /* /dev/hd */ | ||
90 | rw_ttyx, /* /dev/ttyx */ | ||
91 | rw_tty, /* /dev/tty */ | ||
92 | NULL, /* /dev/lp */ | ||
93 | NULL}; /* unnamed pipes */ | ||
94 | |||
95 | int rw_char(int rw,int dev, char * buf, int count, off_t * pos) | ||
96 | { | ||
97 | crw_ptr call_addr; | ||
98 | |||
99 | if (MAJOR(dev)>=NRDEVS) | ||
100 | return -ENODEV; | ||
101 | if (!(call_addr=crw_table[MAJOR(dev)])) | ||
102 | return -ENODEV; | ||
103 | return call_addr(rw,MINOR(dev),buf,count,pos); | ||
104 | } | ||
diff --git a/src/fs/exec.c b/src/fs/exec.c new file mode 100644 index 0000000..d7efa43 --- /dev/null +++ b/src/fs/exec.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * linux/fs/exec.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * #!-checking implemented by tytso. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Demand-loading implemented 01.12.91 - no need to read anything but | ||
13 | * the header into memory. The inode of the executable is put into | ||
14 | * "current->executable", and page faults do the actual loading. Clean. | ||
15 | * | ||
16 | * Once more I can proudly say that linux stood up to being changed: it | ||
17 | * was less than 2 hours work to get demand-loading completely implemented. | ||
18 | */ | ||
19 | |||
20 | #include <errno.h> | ||
21 | #include <string.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <a.out.h> | ||
24 | |||
25 | #include <linux/fs.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <asm/segment.h> | ||
30 | |||
31 | extern int sys_exit(int exit_code); | ||
32 | extern int sys_close(int fd); | ||
33 | |||
34 | /* | ||
35 | * MAX_ARG_PAGES defines the number of pages allocated for arguments | ||
36 | * and envelope for the new program. 32 should suffice, this gives | ||
37 | * a maximum env+arg of 128kB ! | ||
38 | */ | ||
39 | #define MAX_ARG_PAGES 32 | ||
40 | |||
41 | /* | ||
42 | * create_tables() parses the env- and arg-strings in new user | ||
43 | * memory and creates the pointer tables from them, and puts their | ||
44 | * addresses on the "stack", returning the new stack pointer value. | ||
45 | */ | ||
46 | static unsigned long * create_tables(char * p,int argc,int envc) | ||
47 | { | ||
48 | unsigned long *argv,*envp; | ||
49 | unsigned long * sp; | ||
50 | |||
51 | sp = (unsigned long *) (0xfffffffc & (unsigned long) p); | ||
52 | sp -= envc+1; | ||
53 | envp = sp; | ||
54 | sp -= argc+1; | ||
55 | argv = sp; | ||
56 | put_fs_long((unsigned long)envp,--sp); | ||
57 | put_fs_long((unsigned long)argv,--sp); | ||
58 | put_fs_long((unsigned long)argc,--sp); | ||
59 | while (argc-->0) { | ||
60 | put_fs_long((unsigned long) p,argv++); | ||
61 | while (get_fs_byte(p++)) /* nothing */ ; | ||
62 | } | ||
63 | put_fs_long(0,argv); | ||
64 | while (envc-->0) { | ||
65 | put_fs_long((unsigned long) p,envp++); | ||
66 | while (get_fs_byte(p++)) /* nothing */ ; | ||
67 | } | ||
68 | put_fs_long(0,envp); | ||
69 | return sp; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * count() counts the number of arguments/envelopes | ||
74 | */ | ||
75 | static int count(char ** argv) | ||
76 | { | ||
77 | int i=0; | ||
78 | char ** tmp; | ||
79 | |||
80 | if ((tmp = argv)) | ||
81 | while (get_fs_long((unsigned long *) (tmp++))) | ||
82 | i++; | ||
83 | |||
84 | return i; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * 'copy_string()' copies argument/envelope strings from user | ||
89 | * memory to free pages in kernel mem. These are in a format ready | ||
90 | * to be put directly into the top of new user memory. | ||
91 | * | ||
92 | * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies | ||
93 | * whether the string and the string array are from user or kernel segments: | ||
94 | * | ||
95 | * from_kmem argv * argv ** | ||
96 | * 0 user space user space | ||
97 | * 1 kernel space user space | ||
98 | * 2 kernel space kernel space | ||
99 | * | ||
100 | * We do this by playing games with the fs segment register. Since it | ||
101 | * it is expensive to load a segment register, we try to avoid calling | ||
102 | * set_fs() unless we absolutely have to. | ||
103 | */ | ||
104 | static unsigned long copy_strings(int argc,char ** argv,unsigned long *page, | ||
105 | unsigned long p, int from_kmem) | ||
106 | { | ||
107 | char *tmp, *pag=NULL; | ||
108 | int len, offset = 0; | ||
109 | unsigned long old_fs, new_fs; | ||
110 | |||
111 | if (!p) | ||
112 | return 0; /* bullet-proofing */ | ||
113 | new_fs = get_ds(); | ||
114 | old_fs = get_fs(); | ||
115 | if (from_kmem==2) | ||
116 | set_fs(new_fs); | ||
117 | while (argc-- > 0) { | ||
118 | if (from_kmem == 1) | ||
119 | set_fs(new_fs); | ||
120 | if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) | ||
121 | panic("argc is wrong"); | ||
122 | if (from_kmem == 1) | ||
123 | set_fs(old_fs); | ||
124 | len=0; /* remember zero-padding */ | ||
125 | do { | ||
126 | len++; | ||
127 | } while (get_fs_byte(tmp++)); | ||
128 | if (p-len < 0) { /* this shouldn't happen - 128kB */ | ||
129 | set_fs(old_fs); | ||
130 | return 0; | ||
131 | } | ||
132 | while (len) { | ||
133 | --p; --tmp; --len; | ||
134 | if (--offset < 0) { | ||
135 | offset = p % PAGE_SIZE; | ||
136 | if (from_kmem==2) | ||
137 | set_fs(old_fs); | ||
138 | if (!(pag = (char *) page[p/PAGE_SIZE]) && | ||
139 | !(pag = (char *) (page[p/PAGE_SIZE] = | ||
140 | get_free_page()))) | ||
141 | return 0; | ||
142 | if (from_kmem==2) | ||
143 | set_fs(new_fs); | ||
144 | |||
145 | } | ||
146 | *(pag + offset) = get_fs_byte(tmp); | ||
147 | } | ||
148 | } | ||
149 | if (from_kmem==2) | ||
150 | set_fs(old_fs); | ||
151 | return p; | ||
152 | } | ||
153 | |||
154 | static unsigned long change_ldt(unsigned long text_size,unsigned long * page) | ||
155 | { | ||
156 | unsigned long code_limit,data_limit,code_base,data_base; | ||
157 | int i; | ||
158 | |||
159 | code_limit = text_size+PAGE_SIZE -1; | ||
160 | code_limit &= 0xFFFFF000; | ||
161 | data_limit = 0x4000000; | ||
162 | code_base = get_base(current->ldt[1]); | ||
163 | data_base = code_base; | ||
164 | set_base(current->ldt[1],code_base); | ||
165 | set_limit(current->ldt[1],code_limit); | ||
166 | set_base(current->ldt[2],data_base); | ||
167 | set_limit(current->ldt[2],data_limit); | ||
168 | /* make sure fs points to the NEW data segment */ | ||
169 | __asm__("pushl $0x17\n\tpop %%fs"::); | ||
170 | data_base += data_limit; | ||
171 | for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) { | ||
172 | data_base -= PAGE_SIZE; | ||
173 | if (page[i]) | ||
174 | put_page(page[i],data_base); | ||
175 | } | ||
176 | return data_limit; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * 'do_execve()' executes a new program. | ||
181 | */ | ||
182 | int do_execve(unsigned long * eip,long tmp,char * filename, | ||
183 | char ** argv, char ** envp) | ||
184 | { | ||
185 | struct m_inode * inode; | ||
186 | struct buffer_head * bh; | ||
187 | struct exec ex; | ||
188 | unsigned long page[MAX_ARG_PAGES]; | ||
189 | int i,argc,envc; | ||
190 | int e_uid, e_gid; | ||
191 | int retval; | ||
192 | int sh_bang = 0; | ||
193 | unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4; | ||
194 | |||
195 | if ((0xffff & eip[1]) != 0x000f) | ||
196 | panic("execve called from supervisor mode"); | ||
197 | for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */ | ||
198 | page[i]=0; | ||
199 | if (!(inode=namei(filename))) /* get executables inode */ | ||
200 | return -ENOENT; | ||
201 | argc = count(argv); | ||
202 | envc = count(envp); | ||
203 | |||
204 | restart_interp: | ||
205 | if (!S_ISREG(inode->i_mode)) { /* must be regular file */ | ||
206 | retval = -EACCES; | ||
207 | goto exec_error2; | ||
208 | } | ||
209 | i = inode->i_mode; | ||
210 | e_uid = (i & S_ISUID) ? inode->i_uid : current->euid; | ||
211 | e_gid = (i & S_ISGID) ? inode->i_gid : current->egid; | ||
212 | if (current->euid == inode->i_uid) | ||
213 | i >>= 6; | ||
214 | else if (current->egid == inode->i_gid) | ||
215 | i >>= 3; | ||
216 | if (!(i & 1) && | ||
217 | !((inode->i_mode & 0111) && suser())) { | ||
218 | retval = -ENOEXEC; | ||
219 | goto exec_error2; | ||
220 | } | ||
221 | if (!(bh = bread(inode->i_dev,inode->i_zone[0]))) { | ||
222 | retval = -EACCES; | ||
223 | goto exec_error2; | ||
224 | } | ||
225 | ex = *((struct exec *) bh->b_data); /* read exec-header */ | ||
226 | if ((bh->b_data[0] == '#') && (bh->b_data[1] == '!') && (!sh_bang)) { | ||
227 | /* | ||
228 | * This section does the #! interpretation. | ||
229 | * Sorta complicated, but hopefully it will work. -TYT | ||
230 | */ | ||
231 | |||
232 | char buf[1023], *cp, *interp, *i_name, *i_arg; | ||
233 | unsigned long old_fs; | ||
234 | |||
235 | strncpy(buf, bh->b_data+2, 1022); | ||
236 | brelse(bh); | ||
237 | iput(inode); | ||
238 | buf[1022] = '\0'; | ||
239 | if ((cp = strchr(buf, '\n'))) { | ||
240 | *cp = '\0'; | ||
241 | for (cp = buf; (*cp == ' ') || (*cp == '\t'); cp++); | ||
242 | } | ||
243 | if (!cp || *cp == '\0') { | ||
244 | retval = -ENOEXEC; /* No interpreter name found */ | ||
245 | goto exec_error1; | ||
246 | } | ||
247 | interp = i_name = cp; | ||
248 | i_arg = 0; | ||
249 | for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { | ||
250 | if (*cp == '/') | ||
251 | i_name = cp+1; | ||
252 | } | ||
253 | if (*cp) { | ||
254 | *cp++ = '\0'; | ||
255 | i_arg = cp; | ||
256 | } | ||
257 | /* | ||
258 | * OK, we've parsed out the interpreter name and | ||
259 | * (optional) argument. | ||
260 | */ | ||
261 | if (sh_bang++ == 0) { | ||
262 | p = copy_strings(envc, envp, page, p, 0); | ||
263 | p = copy_strings(--argc, argv+1, page, p, 0); | ||
264 | } | ||
265 | /* | ||
266 | * Splice in (1) the interpreter's name for argv[0] | ||
267 | * (2) (optional) argument to interpreter | ||
268 | * (3) filename of shell script | ||
269 | * | ||
270 | * This is done in reverse order, because of how the | ||
271 | * user environment and arguments are stored. | ||
272 | */ | ||
273 | p = copy_strings(1, &filename, page, p, 1); | ||
274 | argc++; | ||
275 | if (i_arg) { | ||
276 | p = copy_strings(1, &i_arg, page, p, 2); | ||
277 | argc++; | ||
278 | } | ||
279 | p = copy_strings(1, &i_name, page, p, 2); | ||
280 | argc++; | ||
281 | if (!p) { | ||
282 | retval = -ENOMEM; | ||
283 | goto exec_error1; | ||
284 | } | ||
285 | /* | ||
286 | * OK, now restart the process with the interpreter's inode. | ||
287 | */ | ||
288 | old_fs = get_fs(); | ||
289 | set_fs(get_ds()); | ||
290 | if (!(inode=namei(interp))) { /* get executables inode */ | ||
291 | set_fs(old_fs); | ||
292 | retval = -ENOENT; | ||
293 | goto exec_error1; | ||
294 | } | ||
295 | set_fs(old_fs); | ||
296 | goto restart_interp; | ||
297 | } | ||
298 | brelse(bh); | ||
299 | if (N_MAGIC(ex) != ZMAGIC || ex.a_trsize || ex.a_drsize || | ||
300 | ex.a_text+ex.a_data+ex.a_bss>0x3000000 || | ||
301 | inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { | ||
302 | retval = -ENOEXEC; | ||
303 | goto exec_error2; | ||
304 | } | ||
305 | if (N_TXTOFF(ex) != BLOCK_SIZE) { | ||
306 | printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename); | ||
307 | retval = -ENOEXEC; | ||
308 | goto exec_error2; | ||
309 | } | ||
310 | if (!sh_bang) { | ||
311 | p = copy_strings(envc,envp,page,p,0); | ||
312 | p = copy_strings(argc,argv,page,p,0); | ||
313 | if (!p) { | ||
314 | retval = -ENOMEM; | ||
315 | goto exec_error2; | ||
316 | } | ||
317 | } | ||
318 | /* OK, This is the point of no return */ | ||
319 | if (current->executable) | ||
320 | iput(current->executable); | ||
321 | current->executable = inode; | ||
322 | for (i=0 ; i<32 ; i++) | ||
323 | current->sigaction[i].sa_handler = NULL; | ||
324 | for (i=0 ; i<NR_OPEN ; i++) | ||
325 | if ((current->close_on_exec>>i)&1) | ||
326 | sys_close(i); | ||
327 | current->close_on_exec = 0; | ||
328 | free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); | ||
329 | free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); | ||
330 | if (last_task_used_math == current) | ||
331 | last_task_used_math = NULL; | ||
332 | current->used_math = 0; | ||
333 | p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE; | ||
334 | p = (unsigned long) create_tables((char *)p,argc,envc); | ||
335 | current->brk = ex.a_bss + | ||
336 | (current->end_data = ex.a_data + | ||
337 | (current->end_code = ex.a_text)); | ||
338 | current->start_stack = p & 0xfffff000; | ||
339 | current->euid = e_uid; | ||
340 | current->egid = e_gid; | ||
341 | i = ex.a_text+ex.a_data; | ||
342 | while (i&0xfff) | ||
343 | put_fs_byte(0,(char *) (i++)); | ||
344 | eip[0] = ex.a_entry; /* eip, magic happens :-) */ | ||
345 | eip[3] = p; /* stack pointer */ | ||
346 | return 0; | ||
347 | exec_error2: | ||
348 | iput(inode); | ||
349 | exec_error1: | ||
350 | for (i=0 ; i<MAX_ARG_PAGES ; i++) | ||
351 | free_page(page[i]); | ||
352 | return(retval); | ||
353 | } | ||
diff --git a/src/fs/fcntl.c b/src/fs/fcntl.c new file mode 100644 index 0000000..f3a2d29 --- /dev/null +++ b/src/fs/fcntl.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * linux/fs/fcntl.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* #include <string.h> */ | ||
8 | #include <errno.h> | ||
9 | #include <linux/sched.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <asm/segment.h> | ||
12 | |||
13 | #include <fcntl.h> | ||
14 | #include <sys/stat.h> | ||
15 | |||
16 | extern int sys_close(int fd); | ||
17 | |||
18 | static int dupfd(unsigned int fd, unsigned int arg) | ||
19 | { | ||
20 | if (fd >= NR_OPEN || !current->filp[fd]) | ||
21 | return -EBADF; | ||
22 | if (arg >= NR_OPEN) | ||
23 | return -EINVAL; | ||
24 | while (arg < NR_OPEN) | ||
25 | if (current->filp[arg]) | ||
26 | arg++; | ||
27 | else | ||
28 | break; | ||
29 | if (arg >= NR_OPEN) | ||
30 | return -EMFILE; | ||
31 | current->close_on_exec &= ~(1<<arg); | ||
32 | (current->filp[arg] = current->filp[fd])->f_count++; | ||
33 | return arg; | ||
34 | } | ||
35 | |||
36 | int sys_dup2(unsigned int oldfd, unsigned int newfd) | ||
37 | { | ||
38 | sys_close(newfd); | ||
39 | return dupfd(oldfd,newfd); | ||
40 | } | ||
41 | |||
42 | int sys_dup(unsigned int fildes) | ||
43 | { | ||
44 | return dupfd(fildes,0); | ||
45 | } | ||
46 | |||
47 | int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
48 | { | ||
49 | struct file * filp; | ||
50 | |||
51 | if (fd >= NR_OPEN || !(filp = current->filp[fd])) | ||
52 | return -EBADF; | ||
53 | switch (cmd) { | ||
54 | case F_DUPFD: | ||
55 | return dupfd(fd,arg); | ||
56 | case F_GETFD: | ||
57 | return (current->close_on_exec>>fd)&1; | ||
58 | case F_SETFD: | ||
59 | if (arg&1) | ||
60 | current->close_on_exec |= (1<<fd); | ||
61 | else | ||
62 | current->close_on_exec &= ~(1<<fd); | ||
63 | return 0; | ||
64 | case F_GETFL: | ||
65 | return filp->f_flags; | ||
66 | case F_SETFL: | ||
67 | filp->f_flags &= ~(O_APPEND | O_NONBLOCK); | ||
68 | filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); | ||
69 | return 0; | ||
70 | case F_GETLK: case F_SETLK: case F_SETLKW: | ||
71 | return -1; | ||
72 | default: | ||
73 | return -1; | ||
74 | } | ||
75 | } | ||
diff --git a/src/fs/file_dev.c b/src/fs/file_dev.c new file mode 100644 index 0000000..4661b6f --- /dev/null +++ b/src/fs/file_dev.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * linux/fs/file_dev.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | #include <fcntl.h> | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <asm/segment.h> | ||
13 | |||
14 | #define MIN(a,b) (((a)<(b))?(a):(b)) | ||
15 | #define MAX(a,b) (((a)>(b))?(a):(b)) | ||
16 | |||
17 | int file_read(struct m_inode * inode, struct file * filp, char * buf, int count) | ||
18 | { | ||
19 | int left,chars,nr; | ||
20 | struct buffer_head * bh; | ||
21 | |||
22 | if ((left=count)<=0) | ||
23 | return 0; | ||
24 | while (left) { | ||
25 | if ((nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE))) { | ||
26 | if (!(bh=bread(inode->i_dev,nr))) | ||
27 | break; | ||
28 | } else | ||
29 | bh = NULL; | ||
30 | nr = filp->f_pos % BLOCK_SIZE; | ||
31 | chars = MIN( BLOCK_SIZE-nr , left ); | ||
32 | filp->f_pos += chars; | ||
33 | left -= chars; | ||
34 | if (bh) { | ||
35 | char * p = nr + bh->b_data; | ||
36 | while (chars-->0) | ||
37 | put_fs_byte(*(p++),buf++); | ||
38 | brelse(bh); | ||
39 | } else { | ||
40 | while (chars-->0) | ||
41 | put_fs_byte(0,buf++); | ||
42 | } | ||
43 | } | ||
44 | inode->i_atime = CURRENT_TIME; | ||
45 | return (count-left)?(count-left):-ERROR; | ||
46 | } | ||
47 | |||
48 | int file_write(struct m_inode * inode, struct file * filp, char * buf, int count) | ||
49 | { | ||
50 | off_t pos; | ||
51 | int block,c; | ||
52 | struct buffer_head * bh; | ||
53 | char * p; | ||
54 | int i=0; | ||
55 | |||
56 | /* | ||
57 | * ok, append may not work when many processes are writing at the same time | ||
58 | * but so what. That way leads to madness anyway. | ||
59 | */ | ||
60 | if (filp->f_flags & O_APPEND) | ||
61 | pos = inode->i_size; | ||
62 | else | ||
63 | pos = filp->f_pos; | ||
64 | while (i<count) { | ||
65 | if (!(block = create_block(inode,pos/BLOCK_SIZE))) | ||
66 | break; | ||
67 | if (!(bh=bread(inode->i_dev,block))) | ||
68 | break; | ||
69 | c = pos % BLOCK_SIZE; | ||
70 | p = c + bh->b_data; | ||
71 | bh->b_dirt = 1; | ||
72 | c = BLOCK_SIZE-c; | ||
73 | if (c > count-i) c = count-i; | ||
74 | pos += c; | ||
75 | if (pos > inode->i_size) { | ||
76 | inode->i_size = pos; | ||
77 | inode->i_dirt = 1; | ||
78 | } | ||
79 | i += c; | ||
80 | while (c-->0) | ||
81 | *(p++) = get_fs_byte(buf++); | ||
82 | brelse(bh); | ||
83 | } | ||
84 | inode->i_mtime = CURRENT_TIME; | ||
85 | if (!(filp->f_flags & O_APPEND)) { | ||
86 | filp->f_pos = pos; | ||
87 | inode->i_ctime = CURRENT_TIME; | ||
88 | } | ||
89 | return (i?i:-1); | ||
90 | } | ||
diff --git a/src/fs/file_table.c b/src/fs/file_table.c new file mode 100644 index 0000000..e0589ac --- /dev/null +++ b/src/fs/file_table.c | |||
@@ -0,0 +1,9 @@ | |||
1 | /* | ||
2 | * linux/fs/file_table.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <linux/fs.h> | ||
8 | |||
9 | struct file file_table[NR_FILE]; | ||
diff --git a/src/fs/inode.c b/src/fs/inode.c new file mode 100644 index 0000000..d0b1c32 --- /dev/null +++ b/src/fs/inode.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /* | ||
2 | * linux/fs/inode.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <string.h> | ||
8 | #include <sys/stat.h> | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <asm/system.h> | ||
14 | |||
15 | struct m_inode inode_table[NR_INODE]={{0,},}; | ||
16 | |||
17 | static void read_inode(struct m_inode * inode); | ||
18 | static void write_inode(struct m_inode * inode); | ||
19 | |||
20 | static inline void wait_on_inode(struct m_inode * inode) | ||
21 | { | ||
22 | cli(); | ||
23 | while (inode->i_lock) | ||
24 | sleep_on(&inode->i_wait); | ||
25 | sti(); | ||
26 | } | ||
27 | |||
28 | static inline void lock_inode(struct m_inode * inode) | ||
29 | { | ||
30 | cli(); | ||
31 | while (inode->i_lock) | ||
32 | sleep_on(&inode->i_wait); | ||
33 | inode->i_lock=1; | ||
34 | sti(); | ||
35 | } | ||
36 | |||
37 | static inline void unlock_inode(struct m_inode * inode) | ||
38 | { | ||
39 | inode->i_lock=0; | ||
40 | wake_up(&inode->i_wait); | ||
41 | } | ||
42 | |||
43 | void invalidate_inodes(int dev) | ||
44 | { | ||
45 | int i; | ||
46 | struct m_inode * inode; | ||
47 | |||
48 | inode = 0+inode_table; | ||
49 | for(i=0 ; i<NR_INODE ; i++,inode++) { | ||
50 | wait_on_inode(inode); | ||
51 | if (inode->i_dev == dev) { | ||
52 | if (inode->i_count) | ||
53 | printk("inode in use on removed disk\n\r"); | ||
54 | inode->i_dev = inode->i_dirt = 0; | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | void sync_inodes(void) | ||
60 | { | ||
61 | int i; | ||
62 | struct m_inode * inode; | ||
63 | |||
64 | inode = 0+inode_table; | ||
65 | for(i=0 ; i<NR_INODE ; i++,inode++) { | ||
66 | wait_on_inode(inode); | ||
67 | if (inode->i_dirt && !inode->i_pipe) | ||
68 | write_inode(inode); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static int _bmap(struct m_inode * inode,int block,int create) | ||
73 | { | ||
74 | struct buffer_head * bh; | ||
75 | int i; | ||
76 | |||
77 | if (block<0) | ||
78 | panic("_bmap: block<0"); | ||
79 | if (block >= 7+512+512*512) | ||
80 | panic("_bmap: block>big"); | ||
81 | if (block<7) { | ||
82 | if (create && !inode->i_zone[block]) | ||
83 | if ((inode->i_zone[block]=new_block(inode->i_dev))) { | ||
84 | inode->i_ctime=CURRENT_TIME; | ||
85 | inode->i_dirt=1; | ||
86 | } | ||
87 | return inode->i_zone[block]; | ||
88 | } | ||
89 | block -= 7; | ||
90 | if (block<512) { | ||
91 | if (create && !inode->i_zone[7]) | ||
92 | if ((inode->i_zone[7]=new_block(inode->i_dev))) { | ||
93 | inode->i_dirt=1; | ||
94 | inode->i_ctime=CURRENT_TIME; | ||
95 | } | ||
96 | if (!inode->i_zone[7]) | ||
97 | return 0; | ||
98 | if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) | ||
99 | return 0; | ||
100 | i = ((unsigned short *) (bh->b_data))[block]; | ||
101 | if (create && !i) | ||
102 | if ((i=new_block(inode->i_dev))) { | ||
103 | ((unsigned short *) (bh->b_data))[block]=i; | ||
104 | bh->b_dirt=1; | ||
105 | } | ||
106 | brelse(bh); | ||
107 | return i; | ||
108 | } | ||
109 | block -= 512; | ||
110 | if (create && !inode->i_zone[8]) | ||
111 | if ((inode->i_zone[8]=new_block(inode->i_dev))) { | ||
112 | inode->i_dirt=1; | ||
113 | inode->i_ctime=CURRENT_TIME; | ||
114 | } | ||
115 | if (!inode->i_zone[8]) | ||
116 | return 0; | ||
117 | if (!(bh=bread(inode->i_dev,inode->i_zone[8]))) | ||
118 | return 0; | ||
119 | i = ((unsigned short *)bh->b_data)[block>>9]; | ||
120 | if (create && !i) | ||
121 | if ((i=new_block(inode->i_dev))) { | ||
122 | ((unsigned short *) (bh->b_data))[block>>9]=i; | ||
123 | bh->b_dirt=1; | ||
124 | } | ||
125 | brelse(bh); | ||
126 | if (!i) | ||
127 | return 0; | ||
128 | if (!(bh=bread(inode->i_dev,i))) | ||
129 | return 0; | ||
130 | i = ((unsigned short *)bh->b_data)[block&511]; | ||
131 | if (create && !i) | ||
132 | if ((i=new_block(inode->i_dev))) { | ||
133 | ((unsigned short *) (bh->b_data))[block&511]=i; | ||
134 | bh->b_dirt=1; | ||
135 | } | ||
136 | brelse(bh); | ||
137 | return i; | ||
138 | } | ||
139 | |||
140 | int bmap(struct m_inode * inode,int block) | ||
141 | { | ||
142 | return _bmap(inode,block,0); | ||
143 | } | ||
144 | |||
145 | int create_block(struct m_inode * inode, int block) | ||
146 | { | ||
147 | return _bmap(inode,block,1); | ||
148 | } | ||
149 | |||
150 | void iput(struct m_inode * inode) | ||
151 | { | ||
152 | if (!inode) | ||
153 | return; | ||
154 | wait_on_inode(inode); | ||
155 | if (!inode->i_count) | ||
156 | panic("iput: trying to free free inode"); | ||
157 | if (inode->i_pipe) { | ||
158 | wake_up(&inode->i_wait); | ||
159 | if (--inode->i_count) | ||
160 | return; | ||
161 | free_page(inode->i_size); | ||
162 | inode->i_count=0; | ||
163 | inode->i_dirt=0; | ||
164 | inode->i_pipe=0; | ||
165 | return; | ||
166 | } | ||
167 | if (!inode->i_dev) { | ||
168 | inode->i_count--; | ||
169 | return; | ||
170 | } | ||
171 | if (S_ISBLK(inode->i_mode)) { | ||
172 | sync_dev(inode->i_zone[0]); | ||
173 | wait_on_inode(inode); | ||
174 | } | ||
175 | repeat: | ||
176 | if (inode->i_count>1) { | ||
177 | inode->i_count--; | ||
178 | return; | ||
179 | } | ||
180 | if (!inode->i_nlinks) { | ||
181 | truncate(inode); | ||
182 | free_inode(inode); | ||
183 | return; | ||
184 | } | ||
185 | if (inode->i_dirt) { | ||
186 | write_inode(inode); /* we can sleep - so do again */ | ||
187 | wait_on_inode(inode); | ||
188 | goto repeat; | ||
189 | } | ||
190 | inode->i_count--; | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | struct m_inode * get_empty_inode(void) | ||
195 | { | ||
196 | struct m_inode * inode; | ||
197 | static struct m_inode * last_inode = inode_table; | ||
198 | int i; | ||
199 | |||
200 | do { | ||
201 | inode = NULL; | ||
202 | for (i = NR_INODE; i ; i--) { | ||
203 | if (++last_inode >= inode_table + NR_INODE) | ||
204 | last_inode = inode_table; | ||
205 | if (!last_inode->i_count) { | ||
206 | inode = last_inode; | ||
207 | if (!inode->i_dirt && !inode->i_lock) | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | if (!inode) { | ||
212 | for (i=0 ; i<NR_INODE ; i++) | ||
213 | printk("%04x: %6d\t",inode_table[i].i_dev, | ||
214 | inode_table[i].i_num); | ||
215 | panic("No free inodes in mem"); | ||
216 | } | ||
217 | wait_on_inode(inode); | ||
218 | while (inode->i_dirt) { | ||
219 | write_inode(inode); | ||
220 | wait_on_inode(inode); | ||
221 | } | ||
222 | } while (inode->i_count); | ||
223 | memset(inode,0,sizeof(*inode)); | ||
224 | inode->i_count = 1; | ||
225 | return inode; | ||
226 | } | ||
227 | |||
228 | struct m_inode * get_pipe_inode(void) | ||
229 | { | ||
230 | struct m_inode * inode; | ||
231 | |||
232 | if (!(inode = get_empty_inode())) | ||
233 | return NULL; | ||
234 | if (!(inode->i_size=get_free_page())) { | ||
235 | inode->i_count = 0; | ||
236 | return NULL; | ||
237 | } | ||
238 | inode->i_count = 2; /* sum of readers/writers */ | ||
239 | PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; | ||
240 | inode->i_pipe = 1; | ||
241 | return inode; | ||
242 | } | ||
243 | |||
244 | struct m_inode * iget(int dev,int nr) | ||
245 | { | ||
246 | struct m_inode * inode, * empty; | ||
247 | |||
248 | if (!dev) | ||
249 | panic("iget with dev==0"); | ||
250 | empty = get_empty_inode(); | ||
251 | inode = inode_table; | ||
252 | while (inode < NR_INODE+inode_table) { | ||
253 | if (inode->i_dev != dev || inode->i_num != nr) { | ||
254 | inode++; | ||
255 | continue; | ||
256 | } | ||
257 | wait_on_inode(inode); | ||
258 | if (inode->i_dev != dev || inode->i_num != nr) { | ||
259 | inode = inode_table; | ||
260 | continue; | ||
261 | } | ||
262 | inode->i_count++; | ||
263 | if (inode->i_mount) { | ||
264 | int i; | ||
265 | |||
266 | for (i = 0 ; i<NR_SUPER ; i++) | ||
267 | if (super_block[i].s_imount==inode) | ||
268 | break; | ||
269 | if (i >= NR_SUPER) { | ||
270 | printk("Mounted inode hasn't got sb\n"); | ||
271 | if (empty) | ||
272 | iput(empty); | ||
273 | return inode; | ||
274 | } | ||
275 | iput(inode); | ||
276 | dev = super_block[i].s_dev; | ||
277 | nr = ROOT_INO; | ||
278 | inode = inode_table; | ||
279 | continue; | ||
280 | } | ||
281 | if (empty) | ||
282 | iput(empty); | ||
283 | return inode; | ||
284 | } | ||
285 | if (!empty) | ||
286 | return (NULL); | ||
287 | inode=empty; | ||
288 | inode->i_dev = dev; | ||
289 | inode->i_num = nr; | ||
290 | read_inode(inode); | ||
291 | return inode; | ||
292 | } | ||
293 | |||
294 | static void read_inode(struct m_inode * inode) | ||
295 | { | ||
296 | struct super_block * sb; | ||
297 | struct buffer_head * bh; | ||
298 | int block; | ||
299 | |||
300 | lock_inode(inode); | ||
301 | if (!(sb=get_super(inode->i_dev))) | ||
302 | panic("trying to read inode without dev"); | ||
303 | block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + | ||
304 | (inode->i_num-1)/INODES_PER_BLOCK; | ||
305 | if (!(bh=bread(inode->i_dev,block))) | ||
306 | panic("unable to read i-node block"); | ||
307 | *(struct d_inode *)inode = | ||
308 | ((struct d_inode *)bh->b_data) | ||
309 | [(inode->i_num-1)%INODES_PER_BLOCK]; | ||
310 | brelse(bh); | ||
311 | unlock_inode(inode); | ||
312 | } | ||
313 | |||
314 | static void write_inode(struct m_inode * inode) | ||
315 | { | ||
316 | struct super_block * sb; | ||
317 | struct buffer_head * bh; | ||
318 | int block; | ||
319 | |||
320 | lock_inode(inode); | ||
321 | if (!inode->i_dirt || !inode->i_dev) { | ||
322 | unlock_inode(inode); | ||
323 | return; | ||
324 | } | ||
325 | if (!(sb=get_super(inode->i_dev))) | ||
326 | panic("trying to write inode without device"); | ||
327 | block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks + | ||
328 | (inode->i_num-1)/INODES_PER_BLOCK; | ||
329 | if (!(bh=bread(inode->i_dev,block))) | ||
330 | panic("unable to read i-node block"); | ||
331 | ((struct d_inode *)bh->b_data) | ||
332 | [(inode->i_num-1)%INODES_PER_BLOCK] = | ||
333 | *(struct d_inode *)inode; | ||
334 | bh->b_dirt=1; | ||
335 | inode->i_dirt=0; | ||
336 | brelse(bh); | ||
337 | unlock_inode(inode); | ||
338 | } | ||
diff --git a/src/fs/ioctl.c b/src/fs/ioctl.c new file mode 100644 index 0000000..47ce3cb --- /dev/null +++ b/src/fs/ioctl.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * linux/fs/ioctl.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* #include <string.h>*/ | ||
8 | #include <errno.h> | ||
9 | #include <sys/stat.h> | ||
10 | |||
11 | #include <linux/sched.h> | ||
12 | |||
13 | extern int tty_ioctl(int dev, int cmd, int arg); | ||
14 | |||
15 | typedef int (*ioctl_ptr)(int dev,int cmd,int arg); | ||
16 | |||
17 | #define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr))) | ||
18 | |||
19 | static ioctl_ptr ioctl_table[]={ | ||
20 | NULL, /* nodev */ | ||
21 | NULL, /* /dev/mem */ | ||
22 | NULL, /* /dev/fd */ | ||
23 | NULL, /* /dev/hd */ | ||
24 | tty_ioctl, /* /dev/ttyx */ | ||
25 | tty_ioctl, /* /dev/tty */ | ||
26 | NULL, /* /dev/lp */ | ||
27 | NULL}; /* named pipes */ | ||
28 | |||
29 | |||
30 | int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
31 | { | ||
32 | struct file * filp; | ||
33 | int dev,mode; | ||
34 | |||
35 | if (fd >= NR_OPEN || !(filp = current->filp[fd])) | ||
36 | return -EBADF; | ||
37 | mode=filp->f_inode->i_mode; | ||
38 | if (!S_ISCHR(mode) && !S_ISBLK(mode)) | ||
39 | return -EINVAL; | ||
40 | dev = filp->f_inode->i_zone[0]; | ||
41 | if (MAJOR(dev) >= NRDEVS) | ||
42 | return -ENODEV; | ||
43 | if (!ioctl_table[MAJOR(dev)]) | ||
44 | return -ENOTTY; | ||
45 | return ioctl_table[MAJOR(dev)](dev,cmd,arg); | ||
46 | } | ||
diff --git a/src/fs/namei.c b/src/fs/namei.c new file mode 100644 index 0000000..97d0de4 --- /dev/null +++ b/src/fs/namei.c | |||
@@ -0,0 +1,778 @@ | |||
1 | /* | ||
2 | * linux/fs/namei.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Some corrections by tytso. | ||
9 | */ | ||
10 | |||
11 | #include <linux/sched.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/segment.h> | ||
14 | |||
15 | #include <string.h> | ||
16 | #include <fcntl.h> | ||
17 | #include <errno.h> | ||
18 | #include <const.h> | ||
19 | #include <sys/stat.h> | ||
20 | |||
21 | #define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) | ||
22 | |||
23 | /* | ||
24 | * comment out this line if you want names > NAME_LEN chars to be | ||
25 | * truncated. Else they will be disallowed. | ||
26 | */ | ||
27 | /* #define NO_TRUNCATE */ | ||
28 | |||
29 | #define MAY_EXEC 1 | ||
30 | #define MAY_WRITE 2 | ||
31 | #define MAY_READ 4 | ||
32 | |||
33 | /* | ||
34 | * permission() | ||
35 | * | ||
36 | * is used to check for read/write/execute permissions on a file. | ||
37 | * I don't know if we should look at just the euid or both euid and | ||
38 | * uid, but that should be easily changed. | ||
39 | */ | ||
40 | static int permission(struct m_inode * inode,int mask) | ||
41 | { | ||
42 | int mode = inode->i_mode; | ||
43 | |||
44 | /* special case: not even root can read/write a deleted file */ | ||
45 | if (inode->i_dev && !inode->i_nlinks) | ||
46 | return 0; | ||
47 | else if (current->euid==inode->i_uid) | ||
48 | mode >>= 6; | ||
49 | else if (current->egid==inode->i_gid) | ||
50 | mode >>= 3; | ||
51 | if (((mode & mask & 0007) == mask) || suser()) | ||
52 | return 1; | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * ok, we cannot use strncmp, as the name is not in our data space. | ||
58 | * Thus we'll have to use match. No big problem. Match also makes | ||
59 | * some sanity tests. | ||
60 | * | ||
61 | * NOTE! unlike strncmp, match returns 1 for success, 0 for failure. | ||
62 | */ | ||
63 | static int match(int len,const char * name,struct dir_entry * de) | ||
64 | { | ||
65 | register int same ; | ||
66 | |||
67 | if (!de || !de->inode || len > NAME_LEN) | ||
68 | return 0; | ||
69 | if (len < NAME_LEN && de->name[len]) | ||
70 | return 0; | ||
71 | __asm__("cld\n\t" | ||
72 | "fs ; repe ; cmpsb\n\t" | ||
73 | "setz %%al" | ||
74 | :"=a" (same) | ||
75 | :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) | ||
76 | ); | ||
77 | return same; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * find_entry() | ||
82 | * | ||
83 | * finds an entry in the specified directory with the wanted name. It | ||
84 | * returns the cache buffer in which the entry was found, and the entry | ||
85 | * itself (as a parameter - res_dir). It does NOT read the inode of the | ||
86 | * entry - you'll have to do that yourself if you want to. | ||
87 | * | ||
88 | * This also takes care of the few special cases due to '..'-traversal | ||
89 | * over a pseudo-root and a mount point. | ||
90 | */ | ||
91 | static struct buffer_head * find_entry(struct m_inode ** dir, | ||
92 | const char * name, int namelen, struct dir_entry ** res_dir) | ||
93 | { | ||
94 | int entries; | ||
95 | int block,i; | ||
96 | struct buffer_head * bh; | ||
97 | struct dir_entry * de; | ||
98 | struct super_block * sb; | ||
99 | |||
100 | #ifdef NO_TRUNCATE | ||
101 | if (namelen > NAME_LEN) | ||
102 | return NULL; | ||
103 | #else | ||
104 | if (namelen > NAME_LEN) | ||
105 | namelen = NAME_LEN; | ||
106 | #endif | ||
107 | entries = (*dir)->i_size / (sizeof (struct dir_entry)); | ||
108 | *res_dir = NULL; | ||
109 | if (!namelen) | ||
110 | return NULL; | ||
111 | /* check for '..', as we might have to do some "magic" for it */ | ||
112 | if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { | ||
113 | /* '..' in a pseudo-root results in a faked '.' (just change namelen) */ | ||
114 | if ((*dir) == current->root) | ||
115 | namelen=1; | ||
116 | else if ((*dir)->i_num == ROOT_INO) { | ||
117 | /* '..' over a mount-point results in 'dir' being exchanged for the mounted | ||
118 | directory-inode. NOTE! We set mounted, so that we can iput the new dir */ | ||
119 | sb=get_super((*dir)->i_dev); | ||
120 | if (sb->s_imount) { | ||
121 | iput(*dir); | ||
122 | (*dir)=sb->s_imount; | ||
123 | (*dir)->i_count++; | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | if (!(block = (*dir)->i_zone[0])) | ||
128 | return NULL; | ||
129 | if (!(bh = bread((*dir)->i_dev,block))) | ||
130 | return NULL; | ||
131 | i = 0; | ||
132 | de = (struct dir_entry *) bh->b_data; | ||
133 | while (i < entries) { | ||
134 | if ((char *)de >= BLOCK_SIZE+bh->b_data) { | ||
135 | brelse(bh); | ||
136 | bh = NULL; | ||
137 | if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || | ||
138 | !(bh = bread((*dir)->i_dev,block))) { | ||
139 | i += DIR_ENTRIES_PER_BLOCK; | ||
140 | continue; | ||
141 | } | ||
142 | de = (struct dir_entry *) bh->b_data; | ||
143 | } | ||
144 | if (match(namelen,name,de)) { | ||
145 | *res_dir = de; | ||
146 | return bh; | ||
147 | } | ||
148 | de++; | ||
149 | i++; | ||
150 | } | ||
151 | brelse(bh); | ||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * add_entry() | ||
157 | * | ||
158 | * adds a file entry to the specified directory, using the same | ||
159 | * semantics as find_entry(). It returns NULL if it failed. | ||
160 | * | ||
161 | * NOTE!! The inode part of 'de' is left at 0 - which means you | ||
162 | * may not sleep between calling this and putting something into | ||
163 | * the entry, as someone else might have used it while you slept. | ||
164 | */ | ||
165 | static struct buffer_head * add_entry(struct m_inode * dir, | ||
166 | const char * name, int namelen, struct dir_entry ** res_dir) | ||
167 | { | ||
168 | int block,i; | ||
169 | struct buffer_head * bh; | ||
170 | struct dir_entry * de; | ||
171 | |||
172 | *res_dir = NULL; | ||
173 | #ifdef NO_TRUNCATE | ||
174 | if (namelen > NAME_LEN) | ||
175 | return NULL; | ||
176 | #else | ||
177 | if (namelen > NAME_LEN) | ||
178 | namelen = NAME_LEN; | ||
179 | #endif | ||
180 | if (!namelen) | ||
181 | return NULL; | ||
182 | if (!(block = dir->i_zone[0])) | ||
183 | return NULL; | ||
184 | if (!(bh = bread(dir->i_dev,block))) | ||
185 | return NULL; | ||
186 | i = 0; | ||
187 | de = (struct dir_entry *) bh->b_data; | ||
188 | while (1) { | ||
189 | if ((char *)de >= BLOCK_SIZE+bh->b_data) { | ||
190 | brelse(bh); | ||
191 | bh = NULL; | ||
192 | block = create_block(dir,i/DIR_ENTRIES_PER_BLOCK); | ||
193 | if (!block) | ||
194 | return NULL; | ||
195 | if (!(bh = bread(dir->i_dev,block))) { | ||
196 | i += DIR_ENTRIES_PER_BLOCK; | ||
197 | continue; | ||
198 | } | ||
199 | de = (struct dir_entry *) bh->b_data; | ||
200 | } | ||
201 | if (i*sizeof(struct dir_entry) >= dir->i_size) { | ||
202 | de->inode=0; | ||
203 | dir->i_size = (i+1)*sizeof(struct dir_entry); | ||
204 | dir->i_dirt = 1; | ||
205 | dir->i_ctime = CURRENT_TIME; | ||
206 | } | ||
207 | if (!de->inode) { | ||
208 | dir->i_mtime = CURRENT_TIME; | ||
209 | for (i=0; i < NAME_LEN ; i++) | ||
210 | de->name[i]=(i<namelen)?get_fs_byte(name+i):0; | ||
211 | bh->b_dirt = 1; | ||
212 | *res_dir = de; | ||
213 | return bh; | ||
214 | } | ||
215 | de++; | ||
216 | i++; | ||
217 | } | ||
218 | brelse(bh); | ||
219 | return NULL; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * get_dir() | ||
224 | * | ||
225 | * Getdir traverses the pathname until it hits the topmost directory. | ||
226 | * It returns NULL on failure. | ||
227 | */ | ||
228 | static struct m_inode * get_dir(const char * pathname) | ||
229 | { | ||
230 | char c; | ||
231 | const char * thisname; | ||
232 | struct m_inode * inode; | ||
233 | struct buffer_head * bh; | ||
234 | int namelen,inr,idev; | ||
235 | struct dir_entry * de; | ||
236 | |||
237 | if (!current->root || !current->root->i_count) | ||
238 | panic("No root inode"); | ||
239 | if (!current->pwd || !current->pwd->i_count) | ||
240 | panic("No cwd inode"); | ||
241 | if ((c=get_fs_byte(pathname))=='/') { | ||
242 | inode = current->root; | ||
243 | pathname++; | ||
244 | } else if (c) | ||
245 | inode = current->pwd; | ||
246 | else | ||
247 | return NULL; /* empty name is bad */ | ||
248 | inode->i_count++; | ||
249 | while (1) { | ||
250 | thisname = pathname; | ||
251 | if (!S_ISDIR(inode->i_mode) || !permission(inode,MAY_EXEC)) { | ||
252 | iput(inode); | ||
253 | return NULL; | ||
254 | } | ||
255 | for(namelen=0;(c=get_fs_byte(pathname++))&&(c!='/');namelen++) | ||
256 | /* nothing */ ; | ||
257 | if (!c) | ||
258 | return inode; | ||
259 | if (!(bh = find_entry(&inode,thisname,namelen,&de))) { | ||
260 | iput(inode); | ||
261 | return NULL; | ||
262 | } | ||
263 | inr = de->inode; | ||
264 | idev = inode->i_dev; | ||
265 | brelse(bh); | ||
266 | iput(inode); | ||
267 | if (!(inode = iget(idev,inr))) | ||
268 | return NULL; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * dir_namei() | ||
274 | * | ||
275 | * dir_namei() returns the inode of the directory of the | ||
276 | * specified name, and the name within that directory. | ||
277 | */ | ||
278 | static struct m_inode * dir_namei(const char * pathname, | ||
279 | int * namelen, const char ** name) | ||
280 | { | ||
281 | char c; | ||
282 | const char * basename; | ||
283 | struct m_inode * dir; | ||
284 | |||
285 | if (!(dir = get_dir(pathname))) | ||
286 | return NULL; | ||
287 | basename = pathname; | ||
288 | while ((c=get_fs_byte(pathname++))) | ||
289 | if (c=='/') | ||
290 | basename=pathname; | ||
291 | *namelen = pathname-basename-1; | ||
292 | *name = basename; | ||
293 | return dir; | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * namei() | ||
298 | * | ||
299 | * is used by most simple commands to get the inode of a specified name. | ||
300 | * Open, link etc use their own routines, but this is enough for things | ||
301 | * like 'chmod' etc. | ||
302 | */ | ||
303 | struct m_inode * namei(const char * pathname) | ||
304 | { | ||
305 | const char * basename; | ||
306 | int inr,dev,namelen; | ||
307 | struct m_inode * dir; | ||
308 | struct buffer_head * bh; | ||
309 | struct dir_entry * de; | ||
310 | |||
311 | if (!(dir = dir_namei(pathname,&namelen,&basename))) | ||
312 | return NULL; | ||
313 | if (!namelen) /* special case: '/usr/' etc */ | ||
314 | return dir; | ||
315 | bh = find_entry(&dir,basename,namelen,&de); | ||
316 | if (!bh) { | ||
317 | iput(dir); | ||
318 | return NULL; | ||
319 | } | ||
320 | inr = de->inode; | ||
321 | dev = dir->i_dev; | ||
322 | brelse(bh); | ||
323 | iput(dir); | ||
324 | dir=iget(dev,inr); | ||
325 | if (dir) { | ||
326 | dir->i_atime=CURRENT_TIME; | ||
327 | dir->i_dirt=1; | ||
328 | } | ||
329 | return dir; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * open_namei() | ||
334 | * | ||
335 | * namei for open - this is in fact almost the whole open-routine. | ||
336 | */ | ||
337 | int open_namei(const char * pathname, int flag, int mode, | ||
338 | struct m_inode ** res_inode) | ||
339 | { | ||
340 | const char * basename; | ||
341 | int inr,dev,namelen; | ||
342 | struct m_inode * dir, *inode; | ||
343 | struct buffer_head * bh; | ||
344 | struct dir_entry * de; | ||
345 | |||
346 | if ((flag & O_TRUNC) && !(flag & O_ACCMODE)) | ||
347 | flag |= O_WRONLY; | ||
348 | mode &= 0777 & ~current->umask; | ||
349 | mode |= I_REGULAR; | ||
350 | if (!(dir = dir_namei(pathname,&namelen,&basename))) | ||
351 | return -ENOENT; | ||
352 | if (!namelen) { /* special case: '/usr/' etc */ | ||
353 | if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { | ||
354 | *res_inode=dir; | ||
355 | return 0; | ||
356 | } | ||
357 | iput(dir); | ||
358 | return -EISDIR; | ||
359 | } | ||
360 | bh = find_entry(&dir,basename,namelen,&de); | ||
361 | if (!bh) { | ||
362 | if (!(flag & O_CREAT)) { | ||
363 | iput(dir); | ||
364 | return -ENOENT; | ||
365 | } | ||
366 | if (!permission(dir,MAY_WRITE)) { | ||
367 | iput(dir); | ||
368 | return -EACCES; | ||
369 | } | ||
370 | inode = new_inode(dir->i_dev); | ||
371 | if (!inode) { | ||
372 | iput(dir); | ||
373 | return -ENOSPC; | ||
374 | } | ||
375 | inode->i_uid = current->euid; | ||
376 | inode->i_mode = mode; | ||
377 | inode->i_dirt = 1; | ||
378 | bh = add_entry(dir,basename,namelen,&de); | ||
379 | if (!bh) { | ||
380 | inode->i_nlinks--; | ||
381 | iput(inode); | ||
382 | iput(dir); | ||
383 | return -ENOSPC; | ||
384 | } | ||
385 | de->inode = inode->i_num; | ||
386 | bh->b_dirt = 1; | ||
387 | brelse(bh); | ||
388 | iput(dir); | ||
389 | *res_inode = inode; | ||
390 | return 0; | ||
391 | } | ||
392 | inr = de->inode; | ||
393 | dev = dir->i_dev; | ||
394 | brelse(bh); | ||
395 | iput(dir); | ||
396 | if (flag & O_EXCL) | ||
397 | return -EEXIST; | ||
398 | if (!(inode=iget(dev,inr))) | ||
399 | return -EACCES; | ||
400 | if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || | ||
401 | !permission(inode,ACC_MODE(flag))) { | ||
402 | iput(inode); | ||
403 | return -EPERM; | ||
404 | } | ||
405 | inode->i_atime = CURRENT_TIME; | ||
406 | if (flag & O_TRUNC) | ||
407 | truncate(inode); | ||
408 | *res_inode = inode; | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | int sys_mknod(const char * filename, int mode, int dev) | ||
413 | { | ||
414 | const char * basename; | ||
415 | int namelen; | ||
416 | struct m_inode * dir, * inode; | ||
417 | struct buffer_head * bh; | ||
418 | struct dir_entry * de; | ||
419 | |||
420 | if (!suser()) | ||
421 | return -EPERM; | ||
422 | if (!(dir = dir_namei(filename,&namelen,&basename))) | ||
423 | return -ENOENT; | ||
424 | if (!namelen) { | ||
425 | iput(dir); | ||
426 | return -ENOENT; | ||
427 | } | ||
428 | if (!permission(dir,MAY_WRITE)) { | ||
429 | iput(dir); | ||
430 | return -EPERM; | ||
431 | } | ||
432 | bh = find_entry(&dir,basename,namelen,&de); | ||
433 | if (bh) { | ||
434 | brelse(bh); | ||
435 | iput(dir); | ||
436 | return -EEXIST; | ||
437 | } | ||
438 | inode = new_inode(dir->i_dev); | ||
439 | if (!inode) { | ||
440 | iput(dir); | ||
441 | return -ENOSPC; | ||
442 | } | ||
443 | inode->i_mode = mode; | ||
444 | if (S_ISBLK(mode) || S_ISCHR(mode)) | ||
445 | inode->i_zone[0] = dev; | ||
446 | inode->i_mtime = inode->i_atime = CURRENT_TIME; | ||
447 | inode->i_dirt = 1; | ||
448 | bh = add_entry(dir,basename,namelen,&de); | ||
449 | if (!bh) { | ||
450 | iput(dir); | ||
451 | inode->i_nlinks=0; | ||
452 | iput(inode); | ||
453 | return -ENOSPC; | ||
454 | } | ||
455 | de->inode = inode->i_num; | ||
456 | bh->b_dirt = 1; | ||
457 | iput(dir); | ||
458 | iput(inode); | ||
459 | brelse(bh); | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | int sys_mkdir(const char * pathname, int mode) | ||
464 | { | ||
465 | const char * basename; | ||
466 | int namelen; | ||
467 | struct m_inode * dir, * inode; | ||
468 | struct buffer_head * bh, *dir_block; | ||
469 | struct dir_entry * de; | ||
470 | |||
471 | if (!suser()) | ||
472 | return -EPERM; | ||
473 | if (!(dir = dir_namei(pathname,&namelen,&basename))) | ||
474 | return -ENOENT; | ||
475 | if (!namelen) { | ||
476 | iput(dir); | ||
477 | return -ENOENT; | ||
478 | } | ||
479 | if (!permission(dir,MAY_WRITE)) { | ||
480 | iput(dir); | ||
481 | return -EPERM; | ||
482 | } | ||
483 | bh = find_entry(&dir,basename,namelen,&de); | ||
484 | if (bh) { | ||
485 | brelse(bh); | ||
486 | iput(dir); | ||
487 | return -EEXIST; | ||
488 | } | ||
489 | inode = new_inode(dir->i_dev); | ||
490 | if (!inode) { | ||
491 | iput(dir); | ||
492 | return -ENOSPC; | ||
493 | } | ||
494 | inode->i_size = 32; | ||
495 | inode->i_dirt = 1; | ||
496 | inode->i_mtime = inode->i_atime = CURRENT_TIME; | ||
497 | if (!(inode->i_zone[0]=new_block(inode->i_dev))) { | ||
498 | iput(dir); | ||
499 | inode->i_nlinks--; | ||
500 | iput(inode); | ||
501 | return -ENOSPC; | ||
502 | } | ||
503 | inode->i_dirt = 1; | ||
504 | if (!(dir_block=bread(inode->i_dev,inode->i_zone[0]))) { | ||
505 | iput(dir); | ||
506 | free_block(inode->i_dev,inode->i_zone[0]); | ||
507 | inode->i_nlinks--; | ||
508 | iput(inode); | ||
509 | return -ERROR; | ||
510 | } | ||
511 | de = (struct dir_entry *) dir_block->b_data; | ||
512 | de->inode=inode->i_num; | ||
513 | strcpy(de->name,"."); | ||
514 | de++; | ||
515 | de->inode = dir->i_num; | ||
516 | strcpy(de->name,".."); | ||
517 | inode->i_nlinks = 2; | ||
518 | dir_block->b_dirt = 1; | ||
519 | brelse(dir_block); | ||
520 | inode->i_mode = I_DIRECTORY | (mode & 0777 & ~current->umask); | ||
521 | inode->i_dirt = 1; | ||
522 | bh = add_entry(dir,basename,namelen,&de); | ||
523 | if (!bh) { | ||
524 | iput(dir); | ||
525 | free_block(inode->i_dev,inode->i_zone[0]); | ||
526 | inode->i_nlinks=0; | ||
527 | iput(inode); | ||
528 | return -ENOSPC; | ||
529 | } | ||
530 | de->inode = inode->i_num; | ||
531 | bh->b_dirt = 1; | ||
532 | dir->i_nlinks++; | ||
533 | dir->i_dirt = 1; | ||
534 | iput(dir); | ||
535 | iput(inode); | ||
536 | brelse(bh); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | /* | ||
541 | * routine to check that the specified directory is empty (for rmdir) | ||
542 | */ | ||
543 | static int empty_dir(struct m_inode * inode) | ||
544 | { | ||
545 | int nr,block; | ||
546 | int len; | ||
547 | struct buffer_head * bh; | ||
548 | struct dir_entry * de; | ||
549 | |||
550 | len = inode->i_size / sizeof (struct dir_entry); | ||
551 | if (len<2 || !inode->i_zone[0] || | ||
552 | !(bh=bread(inode->i_dev,inode->i_zone[0]))) { | ||
553 | printk("warning - bad directory on dev %04x\n",inode->i_dev); | ||
554 | return 0; | ||
555 | } | ||
556 | de = (struct dir_entry *) bh->b_data; | ||
557 | if (de[0].inode != inode->i_num || !de[1].inode || | ||
558 | strcmp(".",de[0].name) || strcmp("..",de[1].name)) { | ||
559 | printk("warning - bad directory on dev %04x\n",inode->i_dev); | ||
560 | return 0; | ||
561 | } | ||
562 | nr = 2; | ||
563 | de += 2; | ||
564 | while (nr<len) { | ||
565 | if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) { | ||
566 | brelse(bh); | ||
567 | block=bmap(inode,nr/DIR_ENTRIES_PER_BLOCK); | ||
568 | if (!block) { | ||
569 | nr += DIR_ENTRIES_PER_BLOCK; | ||
570 | continue; | ||
571 | } | ||
572 | if (!(bh=bread(inode->i_dev,block))) | ||
573 | return 0; | ||
574 | de = (struct dir_entry *) bh->b_data; | ||
575 | } | ||
576 | if (de->inode) { | ||
577 | brelse(bh); | ||
578 | return 0; | ||
579 | } | ||
580 | de++; | ||
581 | nr++; | ||
582 | } | ||
583 | brelse(bh); | ||
584 | return 1; | ||
585 | } | ||
586 | |||
587 | int sys_rmdir(const char * name) | ||
588 | { | ||
589 | const char * basename; | ||
590 | int namelen; | ||
591 | struct m_inode * dir, * inode; | ||
592 | struct buffer_head * bh; | ||
593 | struct dir_entry * de; | ||
594 | |||
595 | if (!suser()) | ||
596 | return -EPERM; | ||
597 | if (!(dir = dir_namei(name,&namelen,&basename))) | ||
598 | return -ENOENT; | ||
599 | if (!namelen) { | ||
600 | iput(dir); | ||
601 | return -ENOENT; | ||
602 | } | ||
603 | if (!permission(dir,MAY_WRITE)) { | ||
604 | iput(dir); | ||
605 | return -EPERM; | ||
606 | } | ||
607 | bh = find_entry(&dir,basename,namelen,&de); | ||
608 | if (!bh) { | ||
609 | iput(dir); | ||
610 | return -ENOENT; | ||
611 | } | ||
612 | if (!(inode = iget(dir->i_dev, de->inode))) { | ||
613 | iput(dir); | ||
614 | brelse(bh); | ||
615 | return -EPERM; | ||
616 | } | ||
617 | if ((dir->i_mode & S_ISVTX) && current->euid && | ||
618 | inode->i_uid != current->euid) { | ||
619 | iput(dir); | ||
620 | iput(inode); | ||
621 | brelse(bh); | ||
622 | return -EPERM; | ||
623 | } | ||
624 | if (inode->i_dev != dir->i_dev || inode->i_count>1) { | ||
625 | iput(dir); | ||
626 | iput(inode); | ||
627 | brelse(bh); | ||
628 | return -EPERM; | ||
629 | } | ||
630 | if (inode == dir) { /* we may not delete ".", but "../dir" is ok */ | ||
631 | iput(inode); | ||
632 | iput(dir); | ||
633 | brelse(bh); | ||
634 | return -EPERM; | ||
635 | } | ||
636 | if (!S_ISDIR(inode->i_mode)) { | ||
637 | iput(inode); | ||
638 | iput(dir); | ||
639 | brelse(bh); | ||
640 | return -ENOTDIR; | ||
641 | } | ||
642 | if (!empty_dir(inode)) { | ||
643 | iput(inode); | ||
644 | iput(dir); | ||
645 | brelse(bh); | ||
646 | return -ENOTEMPTY; | ||
647 | } | ||
648 | if (inode->i_nlinks != 2) | ||
649 | printk("empty directory has nlink!=2 (%d)",inode->i_nlinks); | ||
650 | de->inode = 0; | ||
651 | bh->b_dirt = 1; | ||
652 | brelse(bh); | ||
653 | inode->i_nlinks=0; | ||
654 | inode->i_dirt=1; | ||
655 | dir->i_nlinks--; | ||
656 | dir->i_ctime = dir->i_mtime = CURRENT_TIME; | ||
657 | dir->i_dirt=1; | ||
658 | iput(dir); | ||
659 | iput(inode); | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | int sys_unlink(const char * name) | ||
664 | { | ||
665 | const char * basename; | ||
666 | int namelen; | ||
667 | struct m_inode * dir, * inode; | ||
668 | struct buffer_head * bh; | ||
669 | struct dir_entry * de; | ||
670 | |||
671 | if (!(dir = dir_namei(name,&namelen,&basename))) | ||
672 | return -ENOENT; | ||
673 | if (!namelen) { | ||
674 | iput(dir); | ||
675 | return -ENOENT; | ||
676 | } | ||
677 | if (!permission(dir,MAY_WRITE)) { | ||
678 | iput(dir); | ||
679 | return -EPERM; | ||
680 | } | ||
681 | bh = find_entry(&dir,basename,namelen,&de); | ||
682 | if (!bh) { | ||
683 | iput(dir); | ||
684 | return -ENOENT; | ||
685 | } | ||
686 | if (!(inode = iget(dir->i_dev, de->inode))) { | ||
687 | iput(dir); | ||
688 | brelse(bh); | ||
689 | return -ENOENT; | ||
690 | } | ||
691 | if ((dir->i_mode & S_ISVTX) && !suser() && | ||
692 | current->euid != inode->i_uid && | ||
693 | current->euid != dir->i_uid) { | ||
694 | iput(dir); | ||
695 | iput(inode); | ||
696 | brelse(bh); | ||
697 | return -EPERM; | ||
698 | } | ||
699 | if (S_ISDIR(inode->i_mode)) { | ||
700 | iput(inode); | ||
701 | iput(dir); | ||
702 | brelse(bh); | ||
703 | return -EPERM; | ||
704 | } | ||
705 | if (!inode->i_nlinks) { | ||
706 | printk("Deleting nonexistent file (%04x:%d), %d\n", | ||
707 | inode->i_dev,inode->i_num,inode->i_nlinks); | ||
708 | inode->i_nlinks=1; | ||
709 | } | ||
710 | de->inode = 0; | ||
711 | bh->b_dirt = 1; | ||
712 | brelse(bh); | ||
713 | inode->i_nlinks--; | ||
714 | inode->i_dirt = 1; | ||
715 | inode->i_ctime = CURRENT_TIME; | ||
716 | iput(inode); | ||
717 | iput(dir); | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | int sys_link(const char * oldname, const char * newname) | ||
722 | { | ||
723 | struct dir_entry * de; | ||
724 | struct m_inode * oldinode, * dir; | ||
725 | struct buffer_head * bh; | ||
726 | const char * basename; | ||
727 | int namelen; | ||
728 | |||
729 | oldinode=namei(oldname); | ||
730 | if (!oldinode) | ||
731 | return -ENOENT; | ||
732 | if (S_ISDIR(oldinode->i_mode)) { | ||
733 | iput(oldinode); | ||
734 | return -EPERM; | ||
735 | } | ||
736 | dir = dir_namei(newname,&namelen,&basename); | ||
737 | if (!dir) { | ||
738 | iput(oldinode); | ||
739 | return -EACCES; | ||
740 | } | ||
741 | if (!namelen) { | ||
742 | iput(oldinode); | ||
743 | iput(dir); | ||
744 | return -EPERM; | ||
745 | } | ||
746 | if (dir->i_dev != oldinode->i_dev) { | ||
747 | iput(dir); | ||
748 | iput(oldinode); | ||
749 | return -EXDEV; | ||
750 | } | ||
751 | if (!permission(dir,MAY_WRITE)) { | ||
752 | iput(dir); | ||
753 | iput(oldinode); | ||
754 | return -EACCES; | ||
755 | } | ||
756 | bh = find_entry(&dir,basename,namelen,&de); | ||
757 | if (bh) { | ||
758 | brelse(bh); | ||
759 | iput(dir); | ||
760 | iput(oldinode); | ||
761 | return -EEXIST; | ||
762 | } | ||
763 | bh = add_entry(dir,basename,namelen,&de); | ||
764 | if (!bh) { | ||
765 | iput(dir); | ||
766 | iput(oldinode); | ||
767 | return -ENOSPC; | ||
768 | } | ||
769 | de->inode = oldinode->i_num; | ||
770 | bh->b_dirt = 1; | ||
771 | brelse(bh); | ||
772 | iput(dir); | ||
773 | oldinode->i_nlinks++; | ||
774 | oldinode->i_ctime = CURRENT_TIME; | ||
775 | oldinode->i_dirt = 1; | ||
776 | iput(oldinode); | ||
777 | return 0; | ||
778 | } | ||
diff --git a/src/fs/open.c b/src/fs/open.c new file mode 100644 index 0000000..cac0082 --- /dev/null +++ b/src/fs/open.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * linux/fs/open.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* #include <string.h> */ | ||
8 | #include <errno.h> | ||
9 | #include <fcntl.h> | ||
10 | #include <sys/types.h> | ||
11 | #include <utime.h> | ||
12 | #include <sys/stat.h> | ||
13 | |||
14 | #include <linux/sched.h> | ||
15 | #include <linux/tty.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <asm/segment.h> | ||
18 | |||
19 | int sys_ustat(int dev, struct ustat * ubuf) | ||
20 | { | ||
21 | return -ENOSYS; | ||
22 | } | ||
23 | |||
24 | int sys_utime(char * filename, struct utimbuf * times) | ||
25 | { | ||
26 | struct m_inode * inode; | ||
27 | long actime,modtime; | ||
28 | |||
29 | if (!(inode=namei(filename))) | ||
30 | return -ENOENT; | ||
31 | if (times) { | ||
32 | actime = get_fs_long((unsigned long *) ×->actime); | ||
33 | modtime = get_fs_long((unsigned long *) ×->modtime); | ||
34 | } else | ||
35 | actime = modtime = CURRENT_TIME; | ||
36 | inode->i_atime = actime; | ||
37 | inode->i_mtime = modtime; | ||
38 | inode->i_dirt = 1; | ||
39 | iput(inode); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * XXX should we use the real or effective uid? BSD uses the real uid, | ||
45 | * so as to make this call useful to setuid programs. | ||
46 | */ | ||
47 | int sys_access(const char * filename,int mode) | ||
48 | { | ||
49 | struct m_inode * inode; | ||
50 | int res, i_mode; | ||
51 | |||
52 | mode &= 0007; | ||
53 | if (!(inode=namei(filename))) | ||
54 | return -EACCES; | ||
55 | i_mode = res = inode->i_mode & 0777; | ||
56 | iput(inode); | ||
57 | if (current->uid == inode->i_uid) | ||
58 | res >>= 6; | ||
59 | else if (current->gid == inode->i_gid) | ||
60 | res >>= 6; | ||
61 | if ((res & 0007 & mode) == mode) | ||
62 | return 0; | ||
63 | /* | ||
64 | * XXX we are doing this test last because we really should be | ||
65 | * swapping the effective with the real user id (temporarily), | ||
66 | * and then calling suser() routine. If we do call the | ||
67 | * suser() routine, it needs to be called last. | ||
68 | */ | ||
69 | if ((!current->uid) && | ||
70 | (!(mode & 1) || (i_mode & 0111))) | ||
71 | return 0; | ||
72 | return -EACCES; | ||
73 | } | ||
74 | |||
75 | int sys_chdir(const char * filename) | ||
76 | { | ||
77 | struct m_inode * inode; | ||
78 | |||
79 | if (!(inode = namei(filename))) | ||
80 | return -ENOENT; | ||
81 | if (!S_ISDIR(inode->i_mode)) { | ||
82 | iput(inode); | ||
83 | return -ENOTDIR; | ||
84 | } | ||
85 | iput(current->pwd); | ||
86 | current->pwd = inode; | ||
87 | return (0); | ||
88 | } | ||
89 | |||
90 | int sys_chroot(const char * filename) | ||
91 | { | ||
92 | struct m_inode * inode; | ||
93 | |||
94 | if (!(inode=namei(filename))) | ||
95 | return -ENOENT; | ||
96 | if (!S_ISDIR(inode->i_mode)) { | ||
97 | iput(inode); | ||
98 | return -ENOTDIR; | ||
99 | } | ||
100 | iput(current->root); | ||
101 | current->root = inode; | ||
102 | return (0); | ||
103 | } | ||
104 | |||
105 | int sys_chmod(const char * filename,int mode) | ||
106 | { | ||
107 | struct m_inode * inode; | ||
108 | |||
109 | if (!(inode=namei(filename))) | ||
110 | return -ENOENT; | ||
111 | if ((current->euid != inode->i_uid) && !suser()) { | ||
112 | iput(inode); | ||
113 | return -EACCES; | ||
114 | } | ||
115 | inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777); | ||
116 | inode->i_dirt = 1; | ||
117 | iput(inode); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | int sys_chown(const char * filename,int uid,int gid) | ||
122 | { | ||
123 | struct m_inode * inode; | ||
124 | |||
125 | if (!(inode=namei(filename))) | ||
126 | return -ENOENT; | ||
127 | if (!suser()) { | ||
128 | iput(inode); | ||
129 | return -EACCES; | ||
130 | } | ||
131 | inode->i_uid=uid; | ||
132 | inode->i_gid=gid; | ||
133 | inode->i_dirt=1; | ||
134 | iput(inode); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | int sys_open(const char * filename,int flag,int mode) | ||
139 | { | ||
140 | struct m_inode * inode; | ||
141 | struct file * f; | ||
142 | int i,fd; | ||
143 | |||
144 | mode &= 0777 & ~current->umask; | ||
145 | for(fd=0 ; fd<NR_OPEN ; fd++) | ||
146 | if (!current->filp[fd]) | ||
147 | break; | ||
148 | if (fd>=NR_OPEN) | ||
149 | return -EINVAL; | ||
150 | current->close_on_exec &= ~(1<<fd); | ||
151 | f=0+file_table; | ||
152 | for (i=0 ; i<NR_FILE ; i++,f++) | ||
153 | if (!f->f_count) break; | ||
154 | if (i>=NR_FILE) | ||
155 | return -EINVAL; | ||
156 | (current->filp[fd]=f)->f_count++; | ||
157 | if ((i=open_namei(filename,flag,mode,&inode))<0) { | ||
158 | current->filp[fd]=NULL; | ||
159 | f->f_count=0; | ||
160 | return i; | ||
161 | } | ||
162 | /* ttys are somewhat special (ttyxx major==4, tty major==5) */ | ||
163 | if (S_ISCHR(inode->i_mode)) { | ||
164 | if (MAJOR(inode->i_zone[0])==4) { | ||
165 | if (current->leader && current->tty<0) { | ||
166 | current->tty = MINOR(inode->i_zone[0]); | ||
167 | tty_table[current->tty].pgrp = current->pgrp; | ||
168 | } | ||
169 | } else if (MAJOR(inode->i_zone[0])==5) | ||
170 | if (current->tty<0) { | ||
171 | iput(inode); | ||
172 | current->filp[fd]=NULL; | ||
173 | f->f_count=0; | ||
174 | return -EPERM; | ||
175 | } | ||
176 | } | ||
177 | /* Likewise with block-devices: check for floppy_change */ | ||
178 | if (S_ISBLK(inode->i_mode)) | ||
179 | check_disk_change(inode->i_zone[0]); | ||
180 | f->f_mode = inode->i_mode; | ||
181 | f->f_flags = flag; | ||
182 | f->f_count = 1; | ||
183 | f->f_inode = inode; | ||
184 | f->f_pos = 0; | ||
185 | return (fd); | ||
186 | } | ||
187 | |||
188 | int sys_creat(const char * pathname, int mode) | ||
189 | { | ||
190 | return sys_open(pathname, O_CREAT | O_TRUNC, mode); | ||
191 | } | ||
192 | |||
193 | int sys_close(unsigned int fd) | ||
194 | { | ||
195 | struct file * filp; | ||
196 | |||
197 | if (fd >= NR_OPEN) | ||
198 | return -EINVAL; | ||
199 | current->close_on_exec &= ~(1<<fd); | ||
200 | if (!(filp = current->filp[fd])) | ||
201 | return -EINVAL; | ||
202 | current->filp[fd] = NULL; | ||
203 | if (filp->f_count == 0) | ||
204 | panic("Close: file count is 0"); | ||
205 | if (--filp->f_count) | ||
206 | return (0); | ||
207 | iput(filp->f_inode); | ||
208 | return (0); | ||
209 | } | ||
diff --git a/src/fs/pipe.c b/src/fs/pipe.c new file mode 100644 index 0000000..dfc4480 --- /dev/null +++ b/src/fs/pipe.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * linux/fs/pipe.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <signal.h> | ||
8 | |||
9 | #include <linux/sched.h> | ||
10 | #include <linux/mm.h> /* for get_free_page */ | ||
11 | #include <asm/segment.h> | ||
12 | |||
13 | int read_pipe(struct m_inode * inode, char * buf, int count) | ||
14 | { | ||
15 | int chars, size, read = 0; | ||
16 | |||
17 | while (count>0) { | ||
18 | while (!(size=PIPE_SIZE(*inode))) { | ||
19 | wake_up(&inode->i_wait); | ||
20 | if (inode->i_count != 2) /* are there any writers? */ | ||
21 | return read; | ||
22 | sleep_on(&inode->i_wait); | ||
23 | } | ||
24 | chars = PAGE_SIZE-PIPE_TAIL(*inode); | ||
25 | if (chars > count) | ||
26 | chars = count; | ||
27 | if (chars > size) | ||
28 | chars = size; | ||
29 | count -= chars; | ||
30 | read += chars; | ||
31 | size = PIPE_TAIL(*inode); | ||
32 | PIPE_TAIL(*inode) += chars; | ||
33 | PIPE_TAIL(*inode) &= (PAGE_SIZE-1); | ||
34 | while (chars-->0) | ||
35 | put_fs_byte(((char *)inode->i_size)[size++],buf++); | ||
36 | } | ||
37 | wake_up(&inode->i_wait); | ||
38 | return read; | ||
39 | } | ||
40 | |||
41 | int write_pipe(struct m_inode * inode, char * buf, int count) | ||
42 | { | ||
43 | int chars, size, written = 0; | ||
44 | |||
45 | while (count>0) { | ||
46 | while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) { | ||
47 | wake_up(&inode->i_wait); | ||
48 | if (inode->i_count != 2) { /* no readers */ | ||
49 | current->signal |= (1<<(SIGPIPE-1)); | ||
50 | return written?written:-1; | ||
51 | } | ||
52 | sleep_on(&inode->i_wait); | ||
53 | } | ||
54 | chars = PAGE_SIZE-PIPE_HEAD(*inode); | ||
55 | if (chars > count) | ||
56 | chars = count; | ||
57 | if (chars > size) | ||
58 | chars = size; | ||
59 | count -= chars; | ||
60 | written += chars; | ||
61 | size = PIPE_HEAD(*inode); | ||
62 | PIPE_HEAD(*inode) += chars; | ||
63 | PIPE_HEAD(*inode) &= (PAGE_SIZE-1); | ||
64 | while (chars-->0) | ||
65 | ((char *)inode->i_size)[size++]=get_fs_byte(buf++); | ||
66 | } | ||
67 | wake_up(&inode->i_wait); | ||
68 | return written; | ||
69 | } | ||
70 | |||
71 | int sys_pipe(unsigned long * fildes) | ||
72 | { | ||
73 | struct m_inode * inode; | ||
74 | struct file * f[2]; | ||
75 | int fd[2]; | ||
76 | int i,j; | ||
77 | |||
78 | j=0; | ||
79 | for(i=0;j<2 && i<NR_FILE;i++) | ||
80 | if (!file_table[i].f_count) | ||
81 | (f[j++]=i+file_table)->f_count++; | ||
82 | if (j==1) | ||
83 | f[0]->f_count=0; | ||
84 | if (j<2) | ||
85 | return -1; | ||
86 | j=0; | ||
87 | for(i=0;j<2 && i<NR_OPEN;i++) | ||
88 | if (!current->filp[i]) { | ||
89 | current->filp[ fd[j]=i ] = f[j]; | ||
90 | j++; | ||
91 | } | ||
92 | if (j==1) | ||
93 | current->filp[fd[0]]=NULL; | ||
94 | if (j<2) { | ||
95 | f[0]->f_count=f[1]->f_count=0; | ||
96 | return -1; | ||
97 | } | ||
98 | if (!(inode=get_pipe_inode())) { | ||
99 | current->filp[fd[0]] = | ||
100 | current->filp[fd[1]] = NULL; | ||
101 | f[0]->f_count = f[1]->f_count = 0; | ||
102 | return -1; | ||
103 | } | ||
104 | f[0]->f_inode = f[1]->f_inode = inode; | ||
105 | f[0]->f_pos = f[1]->f_pos = 0; | ||
106 | f[0]->f_mode = 1; /* read */ | ||
107 | f[1]->f_mode = 2; /* write */ | ||
108 | put_fs_long(fd[0],0+fildes); | ||
109 | put_fs_long(fd[1],1+fildes); | ||
110 | return 0; | ||
111 | } | ||
diff --git a/src/fs/read_write.c b/src/fs/read_write.c new file mode 100644 index 0000000..341274a --- /dev/null +++ b/src/fs/read_write.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * linux/fs/read_write.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <sys/stat.h> | ||
8 | #include <errno.h> | ||
9 | #include <sys/types.h> | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <asm/segment.h> | ||
14 | |||
15 | extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos); | ||
16 | extern int read_pipe(struct m_inode * inode, char * buf, int count); | ||
17 | extern int write_pipe(struct m_inode * inode, char * buf, int count); | ||
18 | extern int block_read(int dev, off_t * pos, char * buf, int count); | ||
19 | extern int block_write(int dev, off_t * pos, char * buf, int count); | ||
20 | extern int file_read(struct m_inode * inode, struct file * filp, | ||
21 | char * buf, int count); | ||
22 | extern int file_write(struct m_inode * inode, struct file * filp, | ||
23 | char * buf, int count); | ||
24 | |||
25 | int sys_lseek(unsigned int fd,off_t offset, int origin) | ||
26 | { | ||
27 | struct file * file; | ||
28 | int tmp; | ||
29 | |||
30 | if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode) | ||
31 | || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev))) | ||
32 | return -EBADF; | ||
33 | if (file->f_inode->i_pipe) | ||
34 | return -ESPIPE; | ||
35 | switch (origin) { | ||
36 | case 0: | ||
37 | if (offset<0) return -EINVAL; | ||
38 | file->f_pos=offset; | ||
39 | break; | ||
40 | case 1: | ||
41 | if (file->f_pos+offset<0) return -EINVAL; | ||
42 | file->f_pos += offset; | ||
43 | break; | ||
44 | case 2: | ||
45 | if ((tmp=file->f_inode->i_size+offset) < 0) | ||
46 | return -EINVAL; | ||
47 | file->f_pos = tmp; | ||
48 | break; | ||
49 | default: | ||
50 | return -EINVAL; | ||
51 | } | ||
52 | return file->f_pos; | ||
53 | } | ||
54 | |||
55 | int sys_read(unsigned int fd,char * buf,int count) | ||
56 | { | ||
57 | struct file * file; | ||
58 | struct m_inode * inode; | ||
59 | |||
60 | if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) | ||
61 | return -EINVAL; | ||
62 | if (!count) | ||
63 | return 0; | ||
64 | verify_area(buf,count); | ||
65 | inode = file->f_inode; | ||
66 | if (inode->i_pipe) | ||
67 | return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; | ||
68 | if (S_ISCHR(inode->i_mode)) | ||
69 | return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); | ||
70 | if (S_ISBLK(inode->i_mode)) | ||
71 | return block_read(inode->i_zone[0],&file->f_pos,buf,count); | ||
72 | if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { | ||
73 | if (count+file->f_pos > inode->i_size) | ||
74 | count = inode->i_size - file->f_pos; | ||
75 | if (count<=0) | ||
76 | return 0; | ||
77 | return file_read(inode,file,buf,count); | ||
78 | } | ||
79 | printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | |||
83 | int sys_write(unsigned int fd,char * buf,int count) | ||
84 | { | ||
85 | struct file * file; | ||
86 | struct m_inode * inode; | ||
87 | |||
88 | if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) | ||
89 | return -EINVAL; | ||
90 | if (!count) | ||
91 | return 0; | ||
92 | inode=file->f_inode; | ||
93 | if (inode->i_pipe) | ||
94 | return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO; | ||
95 | if (S_ISCHR(inode->i_mode)) | ||
96 | return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); | ||
97 | if (S_ISBLK(inode->i_mode)) | ||
98 | return block_write(inode->i_zone[0],&file->f_pos,buf,count); | ||
99 | if (S_ISREG(inode->i_mode)) | ||
100 | return file_write(inode,file,buf,count); | ||
101 | printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); | ||
102 | return -EINVAL; | ||
103 | } | ||
diff --git a/src/fs/stat.c b/src/fs/stat.c new file mode 100644 index 0000000..61a4ceb --- /dev/null +++ b/src/fs/stat.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * linux/fs/stat.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | #include <sys/stat.h> | ||
9 | |||
10 | #include <linux/fs.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/segment.h> | ||
14 | |||
15 | static void cp_stat(struct m_inode * inode, struct stat * statbuf) | ||
16 | { | ||
17 | struct stat tmp; | ||
18 | int i; | ||
19 | |||
20 | verify_area(statbuf,sizeof (* statbuf)); | ||
21 | tmp.st_dev = inode->i_dev; | ||
22 | tmp.st_ino = inode->i_num; | ||
23 | tmp.st_mode = inode->i_mode; | ||
24 | tmp.st_nlink = inode->i_nlinks; | ||
25 | tmp.st_uid = inode->i_uid; | ||
26 | tmp.st_gid = inode->i_gid; | ||
27 | tmp.st_rdev = inode->i_zone[0]; | ||
28 | tmp.st_size = inode->i_size; | ||
29 | tmp.st_atime = inode->i_atime; | ||
30 | tmp.st_mtime = inode->i_mtime; | ||
31 | tmp.st_ctime = inode->i_ctime; | ||
32 | for (i=0 ; i<sizeof (tmp) ; i++) | ||
33 | put_fs_byte(((char *) &tmp)[i],&((char *) statbuf)[i]); | ||
34 | } | ||
35 | |||
36 | int sys_stat(char * filename, struct stat * statbuf) | ||
37 | { | ||
38 | struct m_inode * inode; | ||
39 | |||
40 | if (!(inode=namei(filename))) | ||
41 | return -ENOENT; | ||
42 | cp_stat(inode,statbuf); | ||
43 | iput(inode); | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | int sys_fstat(unsigned int fd, struct stat * statbuf) | ||
48 | { | ||
49 | struct file * f; | ||
50 | struct m_inode * inode; | ||
51 | |||
52 | if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) | ||
53 | return -EBADF; | ||
54 | cp_stat(inode,statbuf); | ||
55 | return 0; | ||
56 | } | ||
diff --git a/src/fs/super.c b/src/fs/super.c new file mode 100644 index 0000000..39c4089 --- /dev/null +++ b/src/fs/super.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * linux/fs/super.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * super.c contains code to handle the super-block tables. | ||
9 | */ | ||
10 | #include <linux/config.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/system.h> | ||
14 | |||
15 | #include <errno.h> | ||
16 | #include <sys/stat.h> | ||
17 | |||
18 | int sync_dev(int dev); | ||
19 | void wait_for_keypress(void); | ||
20 | |||
21 | /* set_bit uses setb, as gas doesn't recognize setc */ | ||
22 | #define set_bit(bitnr,addr) ({ \ | ||
23 | register int __res ; \ | ||
24 | __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \ | ||
25 | __res; }) | ||
26 | |||
27 | struct super_block super_block[NR_SUPER]; | ||
28 | /* this is initialized in init/main.c */ | ||
29 | int ROOT_DEV = 0; | ||
30 | |||
31 | static void lock_super(struct super_block * sb) | ||
32 | { | ||
33 | cli(); | ||
34 | while (sb->s_lock) | ||
35 | sleep_on(&(sb->s_wait)); | ||
36 | sb->s_lock = 1; | ||
37 | sti(); | ||
38 | } | ||
39 | |||
40 | static void free_super(struct super_block * sb) | ||
41 | { | ||
42 | cli(); | ||
43 | sb->s_lock = 0; | ||
44 | wake_up(&(sb->s_wait)); | ||
45 | sti(); | ||
46 | } | ||
47 | |||
48 | static void wait_on_super(struct super_block * sb) | ||
49 | { | ||
50 | cli(); | ||
51 | while (sb->s_lock) | ||
52 | sleep_on(&(sb->s_wait)); | ||
53 | sti(); | ||
54 | } | ||
55 | |||
56 | struct super_block * get_super(int dev) | ||
57 | { | ||
58 | struct super_block * s; | ||
59 | |||
60 | if (!dev) | ||
61 | return NULL; | ||
62 | s = 0+super_block; | ||
63 | while (s < NR_SUPER+super_block) | ||
64 | if (s->s_dev == dev) { | ||
65 | wait_on_super(s); | ||
66 | if (s->s_dev == dev) | ||
67 | return s; | ||
68 | s = 0+super_block; | ||
69 | } else | ||
70 | s++; | ||
71 | return NULL; | ||
72 | } | ||
73 | |||
74 | void put_super(int dev) | ||
75 | { | ||
76 | struct super_block * sb; | ||
77 | /* struct m_inode * inode;*/ | ||
78 | int i; | ||
79 | |||
80 | if (dev == ROOT_DEV) { | ||
81 | printk("root diskette changed: prepare for armageddon\n\r"); | ||
82 | return; | ||
83 | } | ||
84 | if (!(sb = get_super(dev))) | ||
85 | return; | ||
86 | if (sb->s_imount) { | ||
87 | printk("Mounted disk changed - tssk, tssk\n\r"); | ||
88 | return; | ||
89 | } | ||
90 | lock_super(sb); | ||
91 | sb->s_dev = 0; | ||
92 | for(i=0;i<I_MAP_SLOTS;i++) | ||
93 | brelse(sb->s_imap[i]); | ||
94 | for(i=0;i<Z_MAP_SLOTS;i++) | ||
95 | brelse(sb->s_zmap[i]); | ||
96 | free_super(sb); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | static struct super_block * read_super(int dev) | ||
101 | { | ||
102 | struct super_block * s; | ||
103 | struct buffer_head * bh; | ||
104 | int i,block; | ||
105 | |||
106 | if (!dev) | ||
107 | return NULL; | ||
108 | check_disk_change(dev); | ||
109 | if ((s = get_super(dev))) | ||
110 | return s; | ||
111 | for (s = 0+super_block ;; s++) { | ||
112 | if (s >= NR_SUPER+super_block) | ||
113 | return NULL; | ||
114 | if (!s->s_dev) | ||
115 | break; | ||
116 | } | ||
117 | s->s_dev = dev; | ||
118 | s->s_isup = NULL; | ||
119 | s->s_imount = NULL; | ||
120 | s->s_time = 0; | ||
121 | s->s_rd_only = 0; | ||
122 | s->s_dirt = 0; | ||
123 | lock_super(s); | ||
124 | if (!(bh = bread(dev,1))) { | ||
125 | s->s_dev=0; | ||
126 | free_super(s); | ||
127 | return NULL; | ||
128 | } | ||
129 | *((struct d_super_block *) s) = | ||
130 | *((struct d_super_block *) bh->b_data); | ||
131 | brelse(bh); | ||
132 | if (s->s_magic != SUPER_MAGIC) { | ||
133 | s->s_dev = 0; | ||
134 | free_super(s); | ||
135 | return NULL; | ||
136 | } | ||
137 | for (i=0;i<I_MAP_SLOTS;i++) | ||
138 | s->s_imap[i] = NULL; | ||
139 | for (i=0;i<Z_MAP_SLOTS;i++) | ||
140 | s->s_zmap[i] = NULL; | ||
141 | block=2; | ||
142 | for (i=0 ; i < s->s_imap_blocks ; i++) | ||
143 | if ((s->s_imap[i]=bread(dev,block))) | ||
144 | block++; | ||
145 | else | ||
146 | break; | ||
147 | for (i=0 ; i < s->s_zmap_blocks ; i++) | ||
148 | if ((s->s_zmap[i]=bread(dev,block))) | ||
149 | block++; | ||
150 | else | ||
151 | break; | ||
152 | if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) { | ||
153 | for(i=0;i<I_MAP_SLOTS;i++) | ||
154 | brelse(s->s_imap[i]); | ||
155 | for(i=0;i<Z_MAP_SLOTS;i++) | ||
156 | brelse(s->s_zmap[i]); | ||
157 | s->s_dev=0; | ||
158 | free_super(s); | ||
159 | return NULL; | ||
160 | } | ||
161 | s->s_imap[0]->b_data[0] |= 1; | ||
162 | s->s_zmap[0]->b_data[0] |= 1; | ||
163 | free_super(s); | ||
164 | return s; | ||
165 | } | ||
166 | |||
167 | int sys_umount(char * dev_name) | ||
168 | { | ||
169 | struct m_inode * inode; | ||
170 | struct super_block * sb; | ||
171 | int dev; | ||
172 | |||
173 | if (!(inode=namei(dev_name))) | ||
174 | return -ENOENT; | ||
175 | dev = inode->i_zone[0]; | ||
176 | if (!S_ISBLK(inode->i_mode)) { | ||
177 | iput(inode); | ||
178 | return -ENOTBLK; | ||
179 | } | ||
180 | iput(inode); | ||
181 | if (dev==ROOT_DEV) | ||
182 | return -EBUSY; | ||
183 | if (!(sb=get_super(dev)) || !(sb->s_imount)) | ||
184 | return -ENOENT; | ||
185 | if (!sb->s_imount->i_mount) | ||
186 | printk("Mounted inode has i_mount=0\n"); | ||
187 | for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++) | ||
188 | if (inode->i_dev==dev && inode->i_count) | ||
189 | return -EBUSY; | ||
190 | sb->s_imount->i_mount=0; | ||
191 | iput(sb->s_imount); | ||
192 | sb->s_imount = NULL; | ||
193 | iput(sb->s_isup); | ||
194 | sb->s_isup = NULL; | ||
195 | put_super(dev); | ||
196 | sync_dev(dev); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | int sys_mount(char * dev_name, char * dir_name, int rw_flag) | ||
201 | { | ||
202 | struct m_inode * dev_i, * dir_i; | ||
203 | struct super_block * sb; | ||
204 | int dev; | ||
205 | |||
206 | if (!(dev_i=namei(dev_name))) | ||
207 | return -ENOENT; | ||
208 | dev = dev_i->i_zone[0]; | ||
209 | if (!S_ISBLK(dev_i->i_mode)) { | ||
210 | iput(dev_i); | ||
211 | return -EPERM; | ||
212 | } | ||
213 | iput(dev_i); | ||
214 | if (!(dir_i=namei(dir_name))) | ||
215 | return -ENOENT; | ||
216 | if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { | ||
217 | iput(dir_i); | ||
218 | return -EBUSY; | ||
219 | } | ||
220 | if (!S_ISDIR(dir_i->i_mode)) { | ||
221 | iput(dir_i); | ||
222 | return -EPERM; | ||
223 | } | ||
224 | if (!(sb=read_super(dev))) { | ||
225 | iput(dir_i); | ||
226 | return -EBUSY; | ||
227 | } | ||
228 | if (sb->s_imount) { | ||
229 | iput(dir_i); | ||
230 | return -EBUSY; | ||
231 | } | ||
232 | if (dir_i->i_mount) { | ||
233 | iput(dir_i); | ||
234 | return -EPERM; | ||
235 | } | ||
236 | sb->s_imount=dir_i; | ||
237 | dir_i->i_mount=1; | ||
238 | dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ | ||
239 | return 0; /* we do that in umount */ | ||
240 | } | ||
241 | |||
242 | void mount_root(void) | ||
243 | { | ||
244 | int i,free; | ||
245 | struct super_block * p; | ||
246 | struct m_inode * mi; | ||
247 | |||
248 | if (32 != sizeof (struct d_inode)) | ||
249 | panic("bad i-node size"); | ||
250 | for(i=0;i<NR_FILE;i++) | ||
251 | file_table[i].f_count=0; | ||
252 | if (MAJOR(ROOT_DEV) == 2) { | ||
253 | printk("Insert root floppy and press ENTER"); | ||
254 | wait_for_keypress(); | ||
255 | } | ||
256 | for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) { | ||
257 | p->s_dev = 0; | ||
258 | p->s_lock = 0; | ||
259 | p->s_wait = NULL; | ||
260 | } | ||
261 | if (!(p=read_super(ROOT_DEV))) | ||
262 | panic("Unable to mount root"); | ||
263 | if (!(mi=iget(ROOT_DEV,ROOT_INO))) | ||
264 | panic("Unable to read root i-node"); | ||
265 | mi->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ | ||
266 | p->s_isup = p->s_imount = mi; | ||
267 | current->pwd = mi; | ||
268 | current->root = mi; | ||
269 | free=0; | ||
270 | i=p->s_nzones; | ||
271 | while (-- i >= 0) | ||
272 | if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data)) | ||
273 | free++; | ||
274 | printk("%d/%d free blocks\n\r",free,p->s_nzones); | ||
275 | free=0; | ||
276 | i=p->s_ninodes+1; | ||
277 | while (-- i >= 0) | ||
278 | if (!set_bit(i&8191,p->s_imap[i>>13]->b_data)) | ||
279 | free++; | ||
280 | printk("%d/%d free inodes\n\r",free,p->s_ninodes); | ||
281 | } | ||
diff --git a/src/fs/truncate.c b/src/fs/truncate.c new file mode 100644 index 0000000..cb22d5f --- /dev/null +++ b/src/fs/truncate.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * linux/fs/truncate.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <linux/sched.h> | ||
8 | |||
9 | #include <sys/stat.h> | ||
10 | |||
11 | static void free_ind(int dev,int block) | ||
12 | { | ||
13 | struct buffer_head * bh; | ||
14 | unsigned short * p; | ||
15 | int i; | ||
16 | |||
17 | if (!block) | ||
18 | return; | ||
19 | if ((bh=bread(dev,block))) { | ||
20 | p = (unsigned short *) bh->b_data; | ||
21 | for (i=0;i<512;i++,p++) | ||
22 | if (*p) | ||
23 | free_block(dev,*p); | ||
24 | brelse(bh); | ||
25 | } | ||
26 | free_block(dev,block); | ||
27 | } | ||
28 | |||
29 | static void free_dind(int dev,int block) | ||
30 | { | ||
31 | struct buffer_head * bh; | ||
32 | unsigned short * p; | ||
33 | int i; | ||
34 | |||
35 | if (!block) | ||
36 | return; | ||
37 | if ((bh=bread(dev,block))) { | ||
38 | p = (unsigned short *) bh->b_data; | ||
39 | for (i=0;i<512;i++,p++) | ||
40 | if (*p) | ||
41 | free_ind(dev,*p); | ||
42 | brelse(bh); | ||
43 | } | ||
44 | free_block(dev,block); | ||
45 | } | ||
46 | |||
47 | void truncate(struct m_inode * inode) | ||
48 | { | ||
49 | int i; | ||
50 | |||
51 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) | ||
52 | return; | ||
53 | for (i=0;i<7;i++) | ||
54 | if (inode->i_zone[i]) { | ||
55 | free_block(inode->i_dev,inode->i_zone[i]); | ||
56 | inode->i_zone[i]=0; | ||
57 | } | ||
58 | free_ind(inode->i_dev,inode->i_zone[7]); | ||
59 | free_dind(inode->i_dev,inode->i_zone[8]); | ||
60 | inode->i_zone[7] = inode->i_zone[8] = 0; | ||
61 | inode->i_size = 0; | ||
62 | inode->i_dirt = 1; | ||
63 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
64 | } | ||
65 | |||
diff --git a/src/include/a.out.h b/src/include/a.out.h new file mode 100644 index 0000000..3e67974 --- /dev/null +++ b/src/include/a.out.h | |||
@@ -0,0 +1,220 @@ | |||
1 | #ifndef _A_OUT_H | ||
2 | #define _A_OUT_H | ||
3 | |||
4 | #define __GNU_EXEC_MACROS__ | ||
5 | |||
6 | struct exec { | ||
7 | unsigned long a_magic; /* Use macros N_MAGIC, etc for access */ | ||
8 | unsigned a_text; /* length of text, in bytes */ | ||
9 | unsigned a_data; /* length of data, in bytes */ | ||
10 | unsigned a_bss; /* length of uninitialized data area for file, in bytes */ | ||
11 | unsigned a_syms; /* length of symbol table data in file, in bytes */ | ||
12 | unsigned a_entry; /* start address */ | ||
13 | unsigned a_trsize; /* length of relocation info for text, in bytes */ | ||
14 | unsigned a_drsize; /* length of relocation info for data, in bytes */ | ||
15 | }; | ||
16 | |||
17 | #ifndef N_MAGIC | ||
18 | #define N_MAGIC(exec) ((exec).a_magic) | ||
19 | #endif | ||
20 | |||
21 | #ifndef OMAGIC | ||
22 | /* Code indicating object file or impure executable. */ | ||
23 | #define OMAGIC 0407 | ||
24 | /* Code indicating pure executable. */ | ||
25 | #define NMAGIC 0410 | ||
26 | /* Code indicating demand-paged executable. */ | ||
27 | #define ZMAGIC 0413 | ||
28 | #endif /* not OMAGIC */ | ||
29 | |||
30 | #ifndef N_BADMAG | ||
31 | #define N_BADMAG(x) \ | ||
32 | (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ | ||
33 | && N_MAGIC(x) != ZMAGIC) | ||
34 | #endif | ||
35 | |||
36 | #define _N_BADMAG(x) \ | ||
37 | (N_MAGIC(x) != OMAGIC && N_MAGIC(x) != NMAGIC \ | ||
38 | && N_MAGIC(x) != ZMAGIC) | ||
39 | |||
40 | #define _N_HDROFF(x) (SEGMENT_SIZE - sizeof (struct exec)) | ||
41 | |||
42 | #ifndef N_TXTOFF | ||
43 | #define N_TXTOFF(x) \ | ||
44 | (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : sizeof (struct exec)) | ||
45 | #endif | ||
46 | |||
47 | #ifndef N_DATOFF | ||
48 | #define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) | ||
49 | #endif | ||
50 | |||
51 | #ifndef N_TRELOFF | ||
52 | #define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) | ||
53 | #endif | ||
54 | |||
55 | #ifndef N_DRELOFF | ||
56 | #define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) | ||
57 | #endif | ||
58 | |||
59 | #ifndef N_SYMOFF | ||
60 | #define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) | ||
61 | #endif | ||
62 | |||
63 | #ifndef N_STROFF | ||
64 | #define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) | ||
65 | #endif | ||
66 | |||
67 | /* Address of text segment in memory after it is loaded. */ | ||
68 | #ifndef N_TXTADDR | ||
69 | #define N_TXTADDR(x) 0 | ||
70 | #endif | ||
71 | |||
72 | /* Address of data segment in memory after it is loaded. | ||
73 | Note that it is up to you to define SEGMENT_SIZE | ||
74 | on machines not listed here. */ | ||
75 | #if defined(vax) || defined(hp300) || defined(pyr) | ||
76 | #define SEGMENT_SIZE PAGE_SIZE | ||
77 | #endif | ||
78 | #ifdef hp300 | ||
79 | #define PAGE_SIZE 4096 | ||
80 | #endif | ||
81 | #ifdef sony | ||
82 | #define SEGMENT_SIZE 0x2000 | ||
83 | #endif /* Sony. */ | ||
84 | #ifdef is68k | ||
85 | #define SEGMENT_SIZE 0x20000 | ||
86 | #endif | ||
87 | #if defined(m68k) && defined(PORTAR) | ||
88 | #define PAGE_SIZE 0x400 | ||
89 | #define SEGMENT_SIZE PAGE_SIZE | ||
90 | #endif | ||
91 | |||
92 | #define PAGE_SIZE 4096 | ||
93 | #define SEGMENT_SIZE 1024 | ||
94 | |||
95 | #define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) | ||
96 | |||
97 | #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) | ||
98 | |||
99 | #ifndef N_DATADDR | ||
100 | #define N_DATADDR(x) \ | ||
101 | (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ | ||
102 | : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) | ||
103 | #endif | ||
104 | |||
105 | /* Address of bss segment in memory after it is loaded. */ | ||
106 | #ifndef N_BSSADDR | ||
107 | #define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) | ||
108 | #endif | ||
109 | |||
110 | #ifndef N_NLIST_DECLARED | ||
111 | struct nlist { | ||
112 | union { | ||
113 | char *n_name; | ||
114 | struct nlist *n_next; | ||
115 | long n_strx; | ||
116 | } n_un; | ||
117 | unsigned char n_type; | ||
118 | char n_other; | ||
119 | short n_desc; | ||
120 | unsigned long n_value; | ||
121 | }; | ||
122 | #endif | ||
123 | |||
124 | #ifndef N_UNDF | ||
125 | #define N_UNDF 0 | ||
126 | #endif | ||
127 | #ifndef N_ABS | ||
128 | #define N_ABS 2 | ||
129 | #endif | ||
130 | #ifndef N_TEXT | ||
131 | #define N_TEXT 4 | ||
132 | #endif | ||
133 | #ifndef N_DATA | ||
134 | #define N_DATA 6 | ||
135 | #endif | ||
136 | #ifndef N_BSS | ||
137 | #define N_BSS 8 | ||
138 | #endif | ||
139 | #ifndef N_COMM | ||
140 | #define N_COMM 18 | ||
141 | #endif | ||
142 | #ifndef N_FN | ||
143 | #define N_FN 15 | ||
144 | #endif | ||
145 | |||
146 | #ifndef N_EXT | ||
147 | #define N_EXT 1 | ||
148 | #endif | ||
149 | #ifndef N_TYPE | ||
150 | #define N_TYPE 036 | ||
151 | #endif | ||
152 | #ifndef N_STAB | ||
153 | #define N_STAB 0340 | ||
154 | #endif | ||
155 | |||
156 | /* The following type indicates the definition of a symbol as being | ||
157 | an indirect reference to another symbol. The other symbol | ||
158 | appears as an undefined reference, immediately following this symbol. | ||
159 | |||
160 | Indirection is asymmetrical. The other symbol's value will be used | ||
161 | to satisfy requests for the indirect symbol, but not vice versa. | ||
162 | If the other symbol does not have a definition, libraries will | ||
163 | be searched to find a definition. */ | ||
164 | #define N_INDR 0xa | ||
165 | |||
166 | /* The following symbols refer to set elements. | ||
167 | All the N_SET[ATDB] symbols with the same name form one set. | ||
168 | Space is allocated for the set in the text section, and each set | ||
169 | element's value is stored into one word of the space. | ||
170 | The first word of the space is the length of the set (number of elements). | ||
171 | |||
172 | The address of the set is made into an N_SETV symbol | ||
173 | whose name is the same as the name of the set. | ||
174 | This symbol acts like a N_DATA global symbol | ||
175 | in that it can satisfy undefined external references. */ | ||
176 | |||
177 | /* These appear as input to LD, in a .o file. */ | ||
178 | #define N_SETA 0x14 /* Absolute set element symbol */ | ||
179 | #define N_SETT 0x16 /* Text set element symbol */ | ||
180 | #define N_SETD 0x18 /* Data set element symbol */ | ||
181 | #define N_SETB 0x1A /* Bss set element symbol */ | ||
182 | |||
183 | /* This is output from LD. */ | ||
184 | #define N_SETV 0x1C /* Pointer to set vector in data area. */ | ||
185 | |||
186 | #ifndef N_RELOCATION_INFO_DECLARED | ||
187 | |||
188 | /* This structure describes a single relocation to be performed. | ||
189 | The text-relocation section of the file is a vector of these structures, | ||
190 | all of which apply to the text section. | ||
191 | Likewise, the data-relocation section applies to the data section. */ | ||
192 | |||
193 | struct relocation_info | ||
194 | { | ||
195 | /* Address (within segment) to be relocated. */ | ||
196 | int r_address; | ||
197 | /* The meaning of r_symbolnum depends on r_extern. */ | ||
198 | unsigned int r_symbolnum:24; | ||
199 | /* Nonzero means value is a pc-relative offset | ||
200 | and it should be relocated for changes in its own address | ||
201 | as well as for changes in the symbol or section specified. */ | ||
202 | unsigned int r_pcrel:1; | ||
203 | /* Length (as exponent of 2) of the field to be relocated. | ||
204 | Thus, a value of 2 indicates 1<<2 bytes. */ | ||
205 | unsigned int r_length:2; | ||
206 | /* 1 => relocate with value of symbol. | ||
207 | r_symbolnum is the index of the symbol | ||
208 | in file's the symbol table. | ||
209 | 0 => relocate with the address of a segment. | ||
210 | r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS | ||
211 | (the N_EXT bit may be set also, but signifies nothing). */ | ||
212 | unsigned int r_extern:1; | ||
213 | /* Four bits that aren't used, but when writing an object file | ||
214 | it is desirable to clear them. */ | ||
215 | unsigned int r_pad:4; | ||
216 | }; | ||
217 | #endif /* no N_RELOCATION_INFO_DECLARED. */ | ||
218 | |||
219 | |||
220 | #endif /* __A_OUT_GNU_H__ */ | ||
diff --git a/src/include/asm/io.h b/src/include/asm/io.h new file mode 100644 index 0000000..d5cc42a --- /dev/null +++ b/src/include/asm/io.h | |||
@@ -0,0 +1,24 @@ | |||
1 | #define outb(value,port) \ | ||
2 | __asm__ ("outb %%al,%%dx"::"a" (value),"d" (port)) | ||
3 | |||
4 | |||
5 | #define inb(port) ({ \ | ||
6 | unsigned char _v; \ | ||
7 | __asm__ volatile ("inb %%dx,%%al":"=a" (_v):"d" (port)); \ | ||
8 | _v; \ | ||
9 | }) | ||
10 | |||
11 | #define outb_p(value,port) \ | ||
12 | __asm__ ("outb %%al,%%dx\n" \ | ||
13 | "\tjmp 1f\n" \ | ||
14 | "1:\tjmp 1f\n" \ | ||
15 | "1:"::"a" (value),"d" (port)) | ||
16 | |||
17 | #define inb_p(port) ({ \ | ||
18 | unsigned char _v; \ | ||
19 | __asm__ volatile ("inb %%dx,%%al\n" \ | ||
20 | "\tjmp 1f\n" \ | ||
21 | "1:\tjmp 1f\n" \ | ||
22 | "1:":"=a" (_v):"d" (port)); \ | ||
23 | _v; \ | ||
24 | }) | ||
diff --git a/src/include/asm/memory.h b/src/include/asm/memory.h new file mode 100644 index 0000000..8aa6d52 --- /dev/null +++ b/src/include/asm/memory.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* | ||
2 | * NOTE!!! memcpy(dest,src,n) assumes ds=es=normal data segment. This | ||
3 | * goes for all kernel functions (ds=es=kernel space, fs=local data, | ||
4 | * gs=null), as well as for all well-behaving user programs (ds=es= | ||
5 | * user data space). This is NOT a bug, as any user program that changes | ||
6 | * es deserves to die if it isn't careful. | ||
7 | */ | ||
8 | //#define memcpy(dest,src,n) ({ \ | ||
9 | //void * _res = dest; \ | ||
10 | //__asm__ __volatile__ ("cld;rep;movsb" \ | ||
11 | // ::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \ | ||
12 | // ); \ | ||
13 | //_res; \ | ||
14 | //}) | ||
diff --git a/src/include/asm/segment.h b/src/include/asm/segment.h new file mode 100644 index 0000000..94dd102 --- /dev/null +++ b/src/include/asm/segment.h | |||
@@ -0,0 +1,65 @@ | |||
1 | static inline unsigned char get_fs_byte(const char * addr) | ||
2 | { | ||
3 | unsigned register char _v; | ||
4 | |||
5 | __asm__ ("movb %%fs:%1,%0":"=r" (_v):"m" (*addr)); | ||
6 | return _v; | ||
7 | } | ||
8 | |||
9 | static inline unsigned short get_fs_word(const unsigned short *addr) | ||
10 | { | ||
11 | unsigned short _v; | ||
12 | |||
13 | __asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr)); | ||
14 | return _v; | ||
15 | } | ||
16 | |||
17 | static inline unsigned long get_fs_long(const unsigned long *addr) | ||
18 | { | ||
19 | unsigned long _v; | ||
20 | |||
21 | __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \ | ||
22 | return _v; | ||
23 | } | ||
24 | |||
25 | static inline void put_fs_byte(char val,char *addr) | ||
26 | { | ||
27 | __asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr)); | ||
28 | } | ||
29 | |||
30 | static inline void put_fs_word(short val,short * addr) | ||
31 | { | ||
32 | __asm__ ("movw %0,%%fs:%1"::"r" (val),"m" (*addr)); | ||
33 | } | ||
34 | |||
35 | static inline void put_fs_long(unsigned long val,unsigned long * addr) | ||
36 | { | ||
37 | __asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr)); | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | * Someone who knows GNU asm better than I should double check the followig. | ||
42 | * It seems to work, but I don't know if I'm doing something subtly wrong. | ||
43 | * --- TYT, 11/24/91 | ||
44 | * [ nothing wrong here, Linus ] | ||
45 | */ | ||
46 | |||
47 | static inline unsigned long get_fs() | ||
48 | { | ||
49 | unsigned short _v; | ||
50 | __asm__("mov %%fs,%%ax":"=a" (_v):); | ||
51 | return _v; | ||
52 | } | ||
53 | |||
54 | static inline unsigned long get_ds() | ||
55 | { | ||
56 | unsigned short _v; | ||
57 | __asm__("mov %%ds,%%ax":"=a" (_v):); | ||
58 | return _v; | ||
59 | } | ||
60 | |||
61 | static inline void set_fs(unsigned long val) | ||
62 | { | ||
63 | __asm__("mov %0,%%fs"::"a" ((unsigned short) val)); | ||
64 | } | ||
65 | |||
diff --git a/src/include/asm/system.h b/src/include/asm/system.h new file mode 100644 index 0000000..9bc027a --- /dev/null +++ b/src/include/asm/system.h | |||
@@ -0,0 +1,67 @@ | |||
1 | #define move_to_user_mode() \ | ||
2 | __asm__ ("movl %%esp,%%eax\n\t" \ | ||
3 | "pushl $0x17\n\t" \ | ||
4 | "pushl %%eax\n\t" \ | ||
5 | "pushfl\n\t" \ | ||
6 | "pushl $0x0f\n\t" \ | ||
7 | "pushl $1f\n\t" \ | ||
8 | "iret\n" \ | ||
9 | "1:\tmovl $0x17,%%eax\n\t" \ | ||
10 | "movw %%ax,%%ds\n\t" \ | ||
11 | "movw %%ax,%%es\n\t" \ | ||
12 | "movw %%ax,%%fs\n\t" \ | ||
13 | "movw %%ax,%%gs" \ | ||
14 | :::"ax") | ||
15 | |||
16 | #define sti() __asm__ ("sti"::) | ||
17 | #define cli() __asm__ ("cli"::) | ||
18 | #define nop() __asm__ ("nop"::) | ||
19 | |||
20 | #define iret() __asm__ ("iret"::) | ||
21 | |||
22 | #define _set_gate(gate_addr,type,dpl,addr) \ | ||
23 | __asm__ ("movw %%dx,%%ax\n\t" \ | ||
24 | "movw %0,%%dx\n\t" \ | ||
25 | "movl %%eax,%1\n\t" \ | ||
26 | "movl %%edx,%2" \ | ||
27 | : \ | ||
28 | : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ | ||
29 | "o" (*((char *) (gate_addr))), \ | ||
30 | "o" (*(4+(char *) (gate_addr))), \ | ||
31 | "d" ((char *) (addr)),"a" (0x00080000)) | ||
32 | |||
33 | #define set_intr_gate(n,addr) \ | ||
34 | _set_gate(&idt[n],14,0,addr) | ||
35 | |||
36 | #define set_trap_gate(n,addr) \ | ||
37 | _set_gate(&idt[n],15,0,addr) | ||
38 | |||
39 | #define set_system_gate(n,addr) \ | ||
40 | _set_gate(&idt[n],15,3,addr) | ||
41 | |||
42 | #define _set_seg_desc(gate_addr,type,dpl,base,limit) {\ | ||
43 | *(gate_addr) = ((base) & 0xff000000) | \ | ||
44 | (((base) & 0x00ff0000)>>16) | \ | ||
45 | ((limit) & 0xf0000) | \ | ||
46 | ((dpl)<<13) | \ | ||
47 | (0x00408000) | \ | ||
48 | ((type)<<8); \ | ||
49 | *((gate_addr)+1) = (((base) & 0x0000ffff)<<16) | \ | ||
50 | ((limit) & 0x0ffff); } | ||
51 | |||
52 | #define _set_tssldt_desc(n,addr,type) \ | ||
53 | __asm__ ("movw $104,%1\n\t" \ | ||
54 | "movw %%ax,%2\n\t" \ | ||
55 | "rorl $16,%%eax\n\t" \ | ||
56 | "movb %%al,%3\n\t" \ | ||
57 | "movb $" type ",%4\n\t" \ | ||
58 | "movb $0x00,%5\n\t" \ | ||
59 | "movb %%ah,%6\n\t" \ | ||
60 | "rorl $16,%%eax" \ | ||
61 | ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \ | ||
62 | "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \ | ||
63 | ) | ||
64 | |||
65 | #define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x89") | ||
66 | #define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x82") | ||
67 | |||
diff --git a/src/include/const.h b/src/include/const.h new file mode 100644 index 0000000..7828e61 --- /dev/null +++ b/src/include/const.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef _CONST_H | ||
2 | #define _CONST_H | ||
3 | |||
4 | #define BUFFER_END 0x200000 | ||
5 | |||
6 | #define I_TYPE 0170000 | ||
7 | #define I_DIRECTORY 0040000 | ||
8 | #define I_REGULAR 0100000 | ||
9 | #define I_BLOCK_SPECIAL 0060000 | ||
10 | #define I_CHAR_SPECIAL 0020000 | ||
11 | #define I_NAMED_PIPE 0010000 | ||
12 | #define I_SET_UID_BIT 0004000 | ||
13 | #define I_SET_GID_BIT 0002000 | ||
14 | |||
15 | #endif | ||
diff --git a/src/include/ctype.h b/src/include/ctype.h new file mode 100644 index 0000000..7acf55d --- /dev/null +++ b/src/include/ctype.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef _CTYPE_H | ||
2 | #define _CTYPE_H | ||
3 | |||
4 | #define _U 0x01 /* upper */ | ||
5 | #define _L 0x02 /* lower */ | ||
6 | #define _D 0x04 /* digit */ | ||
7 | #define _C 0x08 /* cntrl */ | ||
8 | #define _P 0x10 /* punct */ | ||
9 | #define _S 0x20 /* white space (space/lf/tab) */ | ||
10 | #define _X 0x40 /* hex digit */ | ||
11 | #define _SP 0x80 /* hard space (0x20) */ | ||
12 | |||
13 | extern unsigned char _ctype[]; | ||
14 | extern char _ctmp; | ||
15 | |||
16 | #define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D)) | ||
17 | #define isalpha(c) ((_ctype+1)[c]&(_U|_L)) | ||
18 | #define iscntrl(c) ((_ctype+1)[c]&(_C)) | ||
19 | #define isdigit(c) ((_ctype+1)[c]&(_D)) | ||
20 | #define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D)) | ||
21 | #define islower(c) ((_ctype+1)[c]&(_L)) | ||
22 | #define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP)) | ||
23 | #define ispunct(c) ((_ctype+1)[c]&(_P)) | ||
24 | #define isspace(c) ((_ctype+1)[c]&(_S)) | ||
25 | #define isupper(c) ((_ctype+1)[c]&(_U)) | ||
26 | #define isxdigit(c) ((_ctype+1)[c]&(_D|_X)) | ||
27 | |||
28 | #define isascii(c) (((unsigned) c)<=0x7f) | ||
29 | #define toascii(c) (((unsigned) c)&0x7f) | ||
30 | |||
31 | #define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp) | ||
32 | #define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp) | ||
33 | |||
34 | #endif | ||
diff --git a/src/include/errno.h b/src/include/errno.h new file mode 100644 index 0000000..c282f69 --- /dev/null +++ b/src/include/errno.h | |||
@@ -0,0 +1,60 @@ | |||
1 | #ifndef _ERRNO_H | ||
2 | #define _ERRNO_H | ||
3 | |||
4 | /* | ||
5 | * ok, as I hadn't got any other source of information about | ||
6 | * possible error numbers, I was forced to use the same numbers | ||
7 | * as minix. | ||
8 | * Hopefully these are posix or something. I wouldn't know (and posix | ||
9 | * isn't telling me - they want $$$ for their f***ing standard). | ||
10 | * | ||
11 | * We don't use the _SIGN cludge of minix, so kernel returns must | ||
12 | * see to the sign by themselves. | ||
13 | * | ||
14 | * NOTE! Remember to change strerror() if you change this file! | ||
15 | */ | ||
16 | |||
17 | extern int errno; | ||
18 | |||
19 | #define ERROR 99 | ||
20 | #define EPERM 1 | ||
21 | #define ENOENT 2 | ||
22 | #define ESRCH 3 | ||
23 | #define EINTR 4 | ||
24 | #define EIO 5 | ||
25 | #define ENXIO 6 | ||
26 | #define E2BIG 7 | ||
27 | #define ENOEXEC 8 | ||
28 | #define EBADF 9 | ||
29 | #define ECHILD 10 | ||
30 | #define EAGAIN 11 | ||
31 | #define ENOMEM 12 | ||
32 | #define EACCES 13 | ||
33 | #define EFAULT 14 | ||
34 | #define ENOTBLK 15 | ||
35 | #define EBUSY 16 | ||
36 | #define EEXIST 17 | ||
37 | #define EXDEV 18 | ||
38 | #define ENODEV 19 | ||
39 | #define ENOTDIR 20 | ||
40 | #define EISDIR 21 | ||
41 | #define EINVAL 22 | ||
42 | #define ENFILE 23 | ||
43 | #define EMFILE 24 | ||
44 | #define ENOTTY 25 | ||
45 | #define ETXTBSY 26 | ||
46 | #define EFBIG 27 | ||
47 | #define ENOSPC 28 | ||
48 | #define ESPIPE 29 | ||
49 | #define EROFS 30 | ||
50 | #define EMLINK 31 | ||
51 | #define EPIPE 32 | ||
52 | #define EDOM 33 | ||
53 | #define ERANGE 34 | ||
54 | #define EDEADLK 35 | ||
55 | #define ENAMETOOLONG 36 | ||
56 | #define ENOLCK 37 | ||
57 | #define ENOSYS 38 | ||
58 | #define ENOTEMPTY 39 | ||
59 | |||
60 | #endif | ||
diff --git a/src/include/fcntl.h b/src/include/fcntl.h new file mode 100644 index 0000000..a5bf9af --- /dev/null +++ b/src/include/fcntl.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef _FCNTL_H | ||
2 | #define _FCNTL_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | |||
6 | /* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ | ||
7 | #define O_ACCMODE 00003 | ||
8 | #define O_RDONLY 00 | ||
9 | #define O_WRONLY 01 | ||
10 | #define O_RDWR 02 | ||
11 | #define O_CREAT 00100 /* not fcntl */ | ||
12 | #define O_EXCL 00200 /* not fcntl */ | ||
13 | #define O_NOCTTY 00400 /* not fcntl */ | ||
14 | #define O_TRUNC 01000 /* not fcntl */ | ||
15 | #define O_APPEND 02000 | ||
16 | #define O_NONBLOCK 04000 /* not fcntl */ | ||
17 | #define O_NDELAY O_NONBLOCK | ||
18 | |||
19 | /* Defines for fcntl-commands. Note that currently | ||
20 | * locking isn't supported, and other things aren't really | ||
21 | * tested. | ||
22 | */ | ||
23 | #define F_DUPFD 0 /* dup */ | ||
24 | #define F_GETFD 1 /* get f_flags */ | ||
25 | #define F_SETFD 2 /* set f_flags */ | ||
26 | #define F_GETFL 3 /* more flags (cloexec) */ | ||
27 | #define F_SETFL 4 | ||
28 | #define F_GETLK 5 /* not implemented */ | ||
29 | #define F_SETLK 6 | ||
30 | #define F_SETLKW 7 | ||
31 | |||
32 | /* for F_[GET|SET]FL */ | ||
33 | #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ | ||
34 | |||
35 | /* Ok, these are locking features, and aren't implemented at any | ||
36 | * level. POSIX wants them. | ||
37 | */ | ||
38 | #define F_RDLCK 0 | ||
39 | #define F_WRLCK 1 | ||
40 | #define F_UNLCK 2 | ||
41 | |||
42 | /* Once again - not implemented, but ... */ | ||
43 | struct flock { | ||
44 | short l_type; | ||
45 | short l_whence; | ||
46 | off_t l_start; | ||
47 | off_t l_len; | ||
48 | pid_t l_pid; | ||
49 | }; | ||
50 | |||
51 | extern int creat(const char * filename,mode_t mode); | ||
52 | extern int fcntl(int fildes,int cmd, ...); | ||
53 | extern int open(const char * filename, int flags, ...); | ||
54 | |||
55 | #endif | ||
diff --git a/src/include/linux/config.h b/src/include/linux/config.h new file mode 100644 index 0000000..819b525 --- /dev/null +++ b/src/include/linux/config.h | |||
@@ -0,0 +1,48 @@ | |||
1 | #ifndef _CONFIG_H | ||
2 | #define _CONFIG_H | ||
3 | |||
4 | /* | ||
5 | * The root-device is no longer hard-coded. You can change the default | ||
6 | * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * define your keyboard here - | ||
11 | * KBD_FINNISH for Finnish keyboards | ||
12 | * KBD_US for US-type | ||
13 | * KBD_GR for German keyboards | ||
14 | * KBD_FR for Frech keyboard | ||
15 | */ | ||
16 | #define KBD_US | ||
17 | /*#define KBD_GR */ | ||
18 | /*#define KBD_FR */ | ||
19 | /*#define KBD_FINNISH */ | ||
20 | |||
21 | /* | ||
22 | * Normally, Linux can get the drive parameters from the BIOS at | ||
23 | * startup, but if this for some unfathomable reason fails, you'd | ||
24 | * be left stranded. For this case, you can define HD_TYPE, which | ||
25 | * contains all necessary info on your harddisk. | ||
26 | * | ||
27 | * The HD_TYPE macro should look like this: | ||
28 | * | ||
29 | * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl} | ||
30 | * | ||
31 | * In case of two harddisks, the info should be sepatated by | ||
32 | * commas: | ||
33 | * | ||
34 | * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl } | ||
35 | */ | ||
36 | /* | ||
37 | This is an example, two drives, first is type 2, second is type 3: | ||
38 | |||
39 | #define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 } | ||
40 | |||
41 | NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives | ||
42 | with more than 8 heads. | ||
43 | |||
44 | If you want the BIOS to tell what kind of drive you have, just | ||
45 | leave HD_TYPE undefined. This is the normal thing to do. | ||
46 | */ | ||
47 | |||
48 | #endif | ||
diff --git a/src/include/linux/fdreg.h b/src/include/linux/fdreg.h new file mode 100644 index 0000000..01355af --- /dev/null +++ b/src/include/linux/fdreg.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * This file contains some defines for the floppy disk controller. | ||
3 | * Various sources. Mostly "IBM Microcomputers: A Programmers | ||
4 | * Handbook", Sanches and Canton. | ||
5 | */ | ||
6 | #ifndef _FDREG_H | ||
7 | #define _FDREG_H | ||
8 | |||
9 | extern int ticks_to_floppy_on(unsigned int nr); | ||
10 | extern void floppy_on(unsigned int nr); | ||
11 | extern void floppy_off(unsigned int nr); | ||
12 | extern void floppy_select(unsigned int nr); | ||
13 | extern void floppy_deselect(unsigned int nr); | ||
14 | |||
15 | /* Fd controller regs. S&C, about page 340 */ | ||
16 | #define FD_STATUS 0x3f4 | ||
17 | #define FD_DATA 0x3f5 | ||
18 | #define FD_DOR 0x3f2 /* Digital Output Register */ | ||
19 | #define FD_DIR 0x3f7 /* Digital Input Register (read) */ | ||
20 | #define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ | ||
21 | |||
22 | /* Bits of main status register */ | ||
23 | #define STATUS_BUSYMASK 0x0F /* drive busy mask */ | ||
24 | #define STATUS_BUSY 0x10 /* FDC busy */ | ||
25 | #define STATUS_DMA 0x20 /* 0- DMA mode */ | ||
26 | #define STATUS_DIR 0x40 /* 0- cpu->fdc */ | ||
27 | #define STATUS_READY 0x80 /* Data reg ready */ | ||
28 | |||
29 | /* Bits of FD_ST0 */ | ||
30 | #define ST0_DS 0x03 /* drive select mask */ | ||
31 | #define ST0_HA 0x04 /* Head (Address) */ | ||
32 | #define ST0_NR 0x08 /* Not Ready */ | ||
33 | #define ST0_ECE 0x10 /* Equipment chech error */ | ||
34 | #define ST0_SE 0x20 /* Seek end */ | ||
35 | #define ST0_INTR 0xC0 /* Interrupt code mask */ | ||
36 | |||
37 | /* Bits of FD_ST1 */ | ||
38 | #define ST1_MAM 0x01 /* Missing Address Mark */ | ||
39 | #define ST1_WP 0x02 /* Write Protect */ | ||
40 | #define ST1_ND 0x04 /* No Data - unreadable */ | ||
41 | #define ST1_OR 0x10 /* OverRun */ | ||
42 | #define ST1_CRC 0x20 /* CRC error in data or addr */ | ||
43 | #define ST1_EOC 0x80 /* End Of Cylinder */ | ||
44 | |||
45 | /* Bits of FD_ST2 */ | ||
46 | #define ST2_MAM 0x01 /* Missing Addess Mark (again) */ | ||
47 | #define ST2_BC 0x02 /* Bad Cylinder */ | ||
48 | #define ST2_SNS 0x04 /* Scan Not Satisfied */ | ||
49 | #define ST2_SEH 0x08 /* Scan Equal Hit */ | ||
50 | #define ST2_WC 0x10 /* Wrong Cylinder */ | ||
51 | #define ST2_CRC 0x20 /* CRC error in data field */ | ||
52 | #define ST2_CM 0x40 /* Control Mark = deleted */ | ||
53 | |||
54 | /* Bits of FD_ST3 */ | ||
55 | #define ST3_HA 0x04 /* Head (Address) */ | ||
56 | #define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ | ||
57 | #define ST3_WP 0x40 /* Write Protect */ | ||
58 | |||
59 | /* Values for FD_COMMAND */ | ||
60 | #define FD_RECALIBRATE 0x07 /* move to track 0 */ | ||
61 | #define FD_SEEK 0x0F /* seek track */ | ||
62 | #define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ | ||
63 | #define FD_WRITE 0xC5 /* write with MT, MFM */ | ||
64 | #define FD_SENSEI 0x08 /* Sense Interrupt Status */ | ||
65 | #define FD_SPECIFY 0x03 /* specify HUT etc */ | ||
66 | |||
67 | /* DMA commands */ | ||
68 | #define DMA_READ 0x46 | ||
69 | #define DMA_WRITE 0x4A | ||
70 | |||
71 | #endif | ||
diff --git a/src/include/linux/fs.h b/src/include/linux/fs.h new file mode 100644 index 0000000..7a90b10 --- /dev/null +++ b/src/include/linux/fs.h | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * This file has definitions for some important file table | ||
3 | * structures etc. | ||
4 | */ | ||
5 | |||
6 | #ifndef _FS_H | ||
7 | #define _FS_H | ||
8 | |||
9 | #include <sys/types.h> | ||
10 | |||
11 | /* devices are as follows: (same as minix, so we can use the minix | ||
12 | * file system. These are major numbers.) | ||
13 | * | ||
14 | * 0 - unused (nodev) | ||
15 | * 1 - /dev/mem | ||
16 | * 2 - /dev/fd | ||
17 | * 3 - /dev/hd | ||
18 | * 4 - /dev/ttyx | ||
19 | * 5 - /dev/tty | ||
20 | * 6 - /dev/lp | ||
21 | * 7 - unnamed pipes | ||
22 | */ | ||
23 | |||
24 | #define IS_SEEKABLE(x) ((x)>=1 && (x)<=3) | ||
25 | |||
26 | #define READ 0 | ||
27 | #define WRITE 1 | ||
28 | #define READA 2 /* read-ahead - don't pause */ | ||
29 | #define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ | ||
30 | |||
31 | void buffer_init(long buffer_end); | ||
32 | |||
33 | #define MAJOR(a) (((unsigned)(a))>>8) | ||
34 | #define MINOR(a) ((a)&0xff) | ||
35 | |||
36 | #define NAME_LEN 14 | ||
37 | #define ROOT_INO 1 | ||
38 | |||
39 | #define I_MAP_SLOTS 8 | ||
40 | #define Z_MAP_SLOTS 8 | ||
41 | #define SUPER_MAGIC 0x137F | ||
42 | |||
43 | #define NR_OPEN 20 | ||
44 | #define NR_INODE 32 | ||
45 | #define NR_FILE 64 | ||
46 | #define NR_SUPER 8 | ||
47 | #define NR_HASH 307 | ||
48 | #define NR_BUFFERS nr_buffers | ||
49 | #define BLOCK_SIZE 1024 | ||
50 | #define BLOCK_SIZE_BITS 10 | ||
51 | #ifndef NULL | ||
52 | #define NULL ((void *) 0) | ||
53 | #endif | ||
54 | |||
55 | #define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode))) | ||
56 | #define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry))) | ||
57 | |||
58 | #define PIPE_HEAD(inode) ((inode).i_zone[0]) | ||
59 | #define PIPE_TAIL(inode) ((inode).i_zone[1]) | ||
60 | #define PIPE_SIZE(inode) ((PIPE_HEAD(inode)-PIPE_TAIL(inode))&(PAGE_SIZE-1)) | ||
61 | #define PIPE_EMPTY(inode) (PIPE_HEAD(inode)==PIPE_TAIL(inode)) | ||
62 | #define PIPE_FULL(inode) (PIPE_SIZE(inode)==(PAGE_SIZE-1)) | ||
63 | #define INC_PIPE(head) \ | ||
64 | __asm__("incl %0\n\tandl $4095,%0"::"m" (head)) | ||
65 | |||
66 | typedef char buffer_block[BLOCK_SIZE]; | ||
67 | |||
68 | struct buffer_head { | ||
69 | char * b_data; /* pointer to data block (1024 bytes) */ | ||
70 | unsigned long b_blocknr; /* block number */ | ||
71 | unsigned short b_dev; /* device (0 = free) */ | ||
72 | unsigned char b_uptodate; | ||
73 | unsigned char b_dirt; /* 0-clean,1-dirty */ | ||
74 | unsigned char b_count; /* users using this block */ | ||
75 | unsigned char b_lock; /* 0 - ok, 1 -locked */ | ||
76 | struct task_struct * b_wait; | ||
77 | struct buffer_head * b_prev; | ||
78 | struct buffer_head * b_next; | ||
79 | struct buffer_head * b_prev_free; | ||
80 | struct buffer_head * b_next_free; | ||
81 | }; | ||
82 | |||
83 | struct d_inode { | ||
84 | unsigned short i_mode; | ||
85 | unsigned short i_uid; | ||
86 | unsigned long i_size; | ||
87 | unsigned long i_time; | ||
88 | unsigned char i_gid; | ||
89 | unsigned char i_nlinks; | ||
90 | unsigned short i_zone[9]; | ||
91 | }; | ||
92 | |||
93 | struct m_inode { | ||
94 | unsigned short i_mode; | ||
95 | unsigned short i_uid; | ||
96 | unsigned long i_size; | ||
97 | unsigned long i_mtime; | ||
98 | unsigned char i_gid; | ||
99 | unsigned char i_nlinks; | ||
100 | unsigned short i_zone[9]; | ||
101 | /* these are in memory also */ | ||
102 | struct task_struct * i_wait; | ||
103 | unsigned long i_atime; | ||
104 | unsigned long i_ctime; | ||
105 | unsigned short i_dev; | ||
106 | unsigned short i_num; | ||
107 | unsigned short i_count; | ||
108 | unsigned char i_lock; | ||
109 | unsigned char i_dirt; | ||
110 | unsigned char i_pipe; | ||
111 | unsigned char i_mount; | ||
112 | unsigned char i_seek; | ||
113 | unsigned char i_update; | ||
114 | }; | ||
115 | |||
116 | struct file { | ||
117 | unsigned short f_mode; | ||
118 | unsigned short f_flags; | ||
119 | unsigned short f_count; | ||
120 | struct m_inode * f_inode; | ||
121 | off_t f_pos; | ||
122 | }; | ||
123 | |||
124 | struct super_block { | ||
125 | unsigned short s_ninodes; | ||
126 | unsigned short s_nzones; | ||
127 | unsigned short s_imap_blocks; | ||
128 | unsigned short s_zmap_blocks; | ||
129 | unsigned short s_firstdatazone; | ||
130 | unsigned short s_log_zone_size; | ||
131 | unsigned long s_max_size; | ||
132 | unsigned short s_magic; | ||
133 | /* These are only in memory */ | ||
134 | struct buffer_head * s_imap[8]; | ||
135 | struct buffer_head * s_zmap[8]; | ||
136 | unsigned short s_dev; | ||
137 | struct m_inode * s_isup; | ||
138 | struct m_inode * s_imount; | ||
139 | unsigned long s_time; | ||
140 | struct task_struct * s_wait; | ||
141 | unsigned char s_lock; | ||
142 | unsigned char s_rd_only; | ||
143 | unsigned char s_dirt; | ||
144 | }; | ||
145 | |||
146 | struct d_super_block { | ||
147 | unsigned short s_ninodes; | ||
148 | unsigned short s_nzones; | ||
149 | unsigned short s_imap_blocks; | ||
150 | unsigned short s_zmap_blocks; | ||
151 | unsigned short s_firstdatazone; | ||
152 | unsigned short s_log_zone_size; | ||
153 | unsigned long s_max_size; | ||
154 | unsigned short s_magic; | ||
155 | }; | ||
156 | |||
157 | struct dir_entry { | ||
158 | unsigned short inode; | ||
159 | char name[NAME_LEN]; | ||
160 | }; | ||
161 | |||
162 | extern struct m_inode inode_table[NR_INODE]; | ||
163 | extern struct file file_table[NR_FILE]; | ||
164 | extern struct super_block super_block[NR_SUPER]; | ||
165 | extern struct buffer_head * start_buffer; | ||
166 | extern int nr_buffers; | ||
167 | |||
168 | extern void check_disk_change(int dev); | ||
169 | extern int floppy_change(unsigned int nr); | ||
170 | extern int ticks_to_floppy_on(unsigned int dev); | ||
171 | extern void floppy_on(unsigned int dev); | ||
172 | extern void floppy_off(unsigned int dev); | ||
173 | extern void truncate(struct m_inode * inode); | ||
174 | extern void sync_inodes(void); | ||
175 | extern void wait_on(struct m_inode * inode); | ||
176 | extern int bmap(struct m_inode * inode,int block); | ||
177 | extern int create_block(struct m_inode * inode,int block); | ||
178 | extern struct m_inode * namei(const char * pathname); | ||
179 | extern int open_namei(const char * pathname, int flag, int mode, | ||
180 | struct m_inode ** res_inode); | ||
181 | extern void iput(struct m_inode * inode); | ||
182 | extern struct m_inode * iget(int dev,int nr); | ||
183 | extern struct m_inode * get_empty_inode(void); | ||
184 | extern struct m_inode * get_pipe_inode(void); | ||
185 | extern struct buffer_head * get_hash_table(int dev, int block); | ||
186 | extern struct buffer_head * getblk(int dev, int block); | ||
187 | extern void ll_rw_block(int rw, struct buffer_head * bh); | ||
188 | extern void brelse(struct buffer_head * buf); | ||
189 | extern struct buffer_head * bread(int dev,int block); | ||
190 | extern void bread_page(unsigned long addr,int dev,int b[4]); | ||
191 | extern struct buffer_head * breada(int dev,int block,...); | ||
192 | extern int new_block(int dev); | ||
193 | extern void free_block(int dev, int block); | ||
194 | extern struct m_inode * new_inode(int dev); | ||
195 | extern void free_inode(struct m_inode * inode); | ||
196 | extern int sync_dev(int dev); | ||
197 | extern struct super_block * get_super(int dev); | ||
198 | extern int ROOT_DEV; | ||
199 | |||
200 | extern void mount_root(void); | ||
201 | |||
202 | #endif | ||
diff --git a/src/include/linux/hdreg.h b/src/include/linux/hdreg.h new file mode 100644 index 0000000..e6c593f --- /dev/null +++ b/src/include/linux/hdreg.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * This file contains some defines for the AT-hd-controller. | ||
3 | * Various sources. Check out some definitions (see comments with | ||
4 | * a ques). | ||
5 | */ | ||
6 | #ifndef _HDREG_H | ||
7 | #define _HDREG_H | ||
8 | |||
9 | /* Hd controller regs. Ref: IBM AT Bios-listing */ | ||
10 | #define HD_DATA 0x1f0 /* _CTL when writing */ | ||
11 | #define HD_ERROR 0x1f1 /* see err-bits */ | ||
12 | #define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ | ||
13 | #define HD_SECTOR 0x1f3 /* starting sector */ | ||
14 | #define HD_LCYL 0x1f4 /* starting cylinder */ | ||
15 | #define HD_HCYL 0x1f5 /* high byte of starting cyl */ | ||
16 | #define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ | ||
17 | #define HD_STATUS 0x1f7 /* see status-bits */ | ||
18 | #define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */ | ||
19 | #define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ | ||
20 | |||
21 | #define HD_CMD 0x3f6 | ||
22 | |||
23 | /* Bits of HD_STATUS */ | ||
24 | #define ERR_STAT 0x01 | ||
25 | #define INDEX_STAT 0x02 | ||
26 | #define ECC_STAT 0x04 /* Corrected error */ | ||
27 | #define DRQ_STAT 0x08 | ||
28 | #define SEEK_STAT 0x10 | ||
29 | #define WRERR_STAT 0x20 | ||
30 | #define READY_STAT 0x40 | ||
31 | #define BUSY_STAT 0x80 | ||
32 | |||
33 | /* Values for HD_COMMAND */ | ||
34 | #define WIN_RESTORE 0x10 | ||
35 | #define WIN_READ 0x20 | ||
36 | #define WIN_WRITE 0x30 | ||
37 | #define WIN_VERIFY 0x40 | ||
38 | #define WIN_FORMAT 0x50 | ||
39 | #define WIN_INIT 0x60 | ||
40 | #define WIN_SEEK 0x70 | ||
41 | #define WIN_DIAGNOSE 0x90 | ||
42 | #define WIN_SPECIFY 0x91 | ||
43 | |||
44 | /* Bits for HD_ERROR */ | ||
45 | #define MARK_ERR 0x01 /* Bad address mark ? */ | ||
46 | #define TRK0_ERR 0x02 /* couldn't find track 0 */ | ||
47 | #define ABRT_ERR 0x04 /* ? */ | ||
48 | #define ID_ERR 0x10 /* ? */ | ||
49 | #define ECC_ERR 0x40 /* ? */ | ||
50 | #define BBD_ERR 0x80 /* ? */ | ||
51 | |||
52 | struct partition { | ||
53 | unsigned char boot_ind; /* 0x80 - active (unused) */ | ||
54 | unsigned char head; /* ? */ | ||
55 | unsigned char sector; /* ? */ | ||
56 | unsigned char cyl; /* ? */ | ||
57 | unsigned char sys_ind; /* ? */ | ||
58 | unsigned char end_head; /* ? */ | ||
59 | unsigned char end_sector; /* ? */ | ||
60 | unsigned char end_cyl; /* ? */ | ||
61 | unsigned int start_sect; /* starting sector counting from 0 */ | ||
62 | unsigned int nr_sects; /* nr of sectors in partition */ | ||
63 | }; | ||
64 | |||
65 | #endif | ||
diff --git a/src/include/linux/head.h b/src/include/linux/head.h new file mode 100644 index 0000000..db3dda2 --- /dev/null +++ b/src/include/linux/head.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef _HEAD_H | ||
2 | #define _HEAD_H | ||
3 | |||
4 | typedef struct desc_struct { | ||
5 | unsigned long a,b; | ||
6 | } desc_table[256]; | ||
7 | |||
8 | extern unsigned long pg_dir[1024]; | ||
9 | extern desc_table idt,gdt; | ||
10 | |||
11 | #define GDT_NUL 0 | ||
12 | #define GDT_CODE 1 | ||
13 | #define GDT_DATA 2 | ||
14 | #define GDT_TMP 3 | ||
15 | |||
16 | #define LDT_NUL 0 | ||
17 | #define LDT_CODE 1 | ||
18 | #define LDT_DATA 2 | ||
19 | |||
20 | #endif | ||
diff --git a/src/include/linux/kernel.h b/src/include/linux/kernel.h new file mode 100644 index 0000000..2a0f916 --- /dev/null +++ b/src/include/linux/kernel.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * 'kernel.h' contains some often-used function prototypes etc | ||
3 | */ | ||
4 | void verify_area(void * addr,int count); | ||
5 | void panic(const char * str); | ||
6 | int printf(const char * fmt, ...); | ||
7 | int printk(const char * fmt, ...); | ||
8 | int tty_write(unsigned ch,char * buf,int count); | ||
9 | void * malloc(unsigned int size); | ||
10 | void free_s(void * obj, int size); | ||
11 | |||
12 | #define free(x) free_s((x), 0) | ||
13 | |||
14 | /* | ||
15 | * This is defined as a macro, but at some point this might become a | ||
16 | * real subroutine that sets a flag if it returns true (to do | ||
17 | * BSD-style accounting where the process is flagged if it uses root | ||
18 | * privs). The implication of this is that you should do normal | ||
19 | * permissions checks first, and check suser() last. | ||
20 | */ | ||
21 | #define suser() (current->euid == 0) | ||
22 | |||
diff --git a/src/include/linux/mm.h b/src/include/linux/mm.h new file mode 100644 index 0000000..5a160f3 --- /dev/null +++ b/src/include/linux/mm.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef _MM_H | ||
2 | #define _MM_H | ||
3 | |||
4 | #define PAGE_SIZE 4096 | ||
5 | |||
6 | extern unsigned long get_free_page(void); | ||
7 | extern unsigned long put_page(unsigned long page,unsigned long address); | ||
8 | extern void free_page(unsigned long addr); | ||
9 | |||
10 | #endif | ||
diff --git a/src/include/linux/sched.h b/src/include/linux/sched.h new file mode 100644 index 0000000..e1b35be --- /dev/null +++ b/src/include/linux/sched.h | |||
@@ -0,0 +1,256 @@ | |||
1 | #ifndef _SCHED_H | ||
2 | #define _SCHED_H | ||
3 | |||
4 | #define NR_TASKS 64 | ||
5 | #define HZ 100 | ||
6 | |||
7 | #define FIRST_TASK task[0] | ||
8 | #define LAST_TASK task[NR_TASKS-1] | ||
9 | |||
10 | #include <linux/head.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <signal.h> | ||
14 | |||
15 | #if (NR_OPEN > 32) | ||
16 | #error "Currently the close-on-exec-flags are in one word, max 32 files/proc" | ||
17 | #endif | ||
18 | |||
19 | #define TASK_RUNNING 0 | ||
20 | #define TASK_INTERRUPTIBLE 1 | ||
21 | #define TASK_UNINTERRUPTIBLE 2 | ||
22 | #define TASK_ZOMBIE 3 | ||
23 | #define TASK_STOPPED 4 | ||
24 | |||
25 | #ifndef NULL | ||
26 | #define NULL ((void *) 0) | ||
27 | #endif | ||
28 | |||
29 | extern int copy_page_tables(unsigned long from, unsigned long to, long size); | ||
30 | extern int free_page_tables(unsigned long from, unsigned long size); | ||
31 | |||
32 | extern void sched_init(void); | ||
33 | extern void schedule(void); | ||
34 | extern void trap_init(void); | ||
35 | #ifndef PANIC | ||
36 | void panic(const char * str); | ||
37 | #endif | ||
38 | extern int tty_write(unsigned minor,char * buf,int count); | ||
39 | |||
40 | typedef int (*fn_ptr)(); | ||
41 | |||
42 | struct i387_struct { | ||
43 | long cwd; | ||
44 | long swd; | ||
45 | long twd; | ||
46 | long fip; | ||
47 | long fcs; | ||
48 | long foo; | ||
49 | long fos; | ||
50 | long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ | ||
51 | }; | ||
52 | |||
53 | struct tss_struct { | ||
54 | long back_link; /* 16 high bits zero */ | ||
55 | long esp0; | ||
56 | long ss0; /* 16 high bits zero */ | ||
57 | long esp1; | ||
58 | long ss1; /* 16 high bits zero */ | ||
59 | long esp2; | ||
60 | long ss2; /* 16 high bits zero */ | ||
61 | long cr3; | ||
62 | long eip; | ||
63 | long eflags; | ||
64 | long eax,ecx,edx,ebx; | ||
65 | long esp; | ||
66 | long ebp; | ||
67 | long esi; | ||
68 | long edi; | ||
69 | long es; /* 16 high bits zero */ | ||
70 | long cs; /* 16 high bits zero */ | ||
71 | long ss; /* 16 high bits zero */ | ||
72 | long ds; /* 16 high bits zero */ | ||
73 | long fs; /* 16 high bits zero */ | ||
74 | long gs; /* 16 high bits zero */ | ||
75 | long ldt; /* 16 high bits zero */ | ||
76 | long trace_bitmap; /* bits: trace 0, bitmap 16-31 */ | ||
77 | struct i387_struct i387; | ||
78 | }; | ||
79 | |||
80 | struct task_struct { | ||
81 | /* these are hardcoded - don't touch */ | ||
82 | long state; /* -1 unrunnable, 0 runnable, >0 stopped */ | ||
83 | long counter; | ||
84 | long priority; | ||
85 | long signal; | ||
86 | struct sigaction sigaction[32]; | ||
87 | long blocked; /* bitmap of masked signals */ | ||
88 | /* various fields */ | ||
89 | int exit_code; | ||
90 | unsigned long start_code,end_code,end_data,brk,start_stack; | ||
91 | long pid,father,pgrp,session,leader; | ||
92 | unsigned short uid,euid,suid; | ||
93 | unsigned short gid,egid,sgid; | ||
94 | long alarm; | ||
95 | long utime,stime,cutime,cstime,start_time; | ||
96 | unsigned short used_math; | ||
97 | /* file system info */ | ||
98 | int tty; /* -1 if no tty, so it must be signed */ | ||
99 | unsigned short umask; | ||
100 | struct m_inode * pwd; | ||
101 | struct m_inode * root; | ||
102 | struct m_inode * executable; | ||
103 | unsigned long close_on_exec; | ||
104 | struct file * filp[NR_OPEN]; | ||
105 | /* ldt for this task 0 - zero 1 - cs 2 - ds&ss */ | ||
106 | struct desc_struct ldt[3]; | ||
107 | /* tss for this task */ | ||
108 | struct tss_struct tss; | ||
109 | }; | ||
110 | |||
111 | /* | ||
112 | * INIT_TASK is used to set up the first task table, touch at | ||
113 | * your own risk!. Base=0, limit=0x9ffff (=640kB) | ||
114 | */ | ||
115 | #define INIT_TASK \ | ||
116 | /* state etc */ { 0,15,15, \ | ||
117 | /* signals */ 0,{{},},0, \ | ||
118 | /* ec,brk... */ 0,0,0,0,0,0, \ | ||
119 | /* pid etc.. */ 0,-1,0,0,0, \ | ||
120 | /* uid etc */ 0,0,0,0,0,0, \ | ||
121 | /* alarm */ 0,0,0,0,0,0, \ | ||
122 | /* math */ 0, \ | ||
123 | /* fs info */ -1,0022,NULL,NULL,NULL,0, \ | ||
124 | /* filp */ {NULL,}, \ | ||
125 | { \ | ||
126 | {0,0}, \ | ||
127 | /* ldt */ {0x9f,0xc0fa00}, \ | ||
128 | {0x9f,0xc0f200}, \ | ||
129 | }, \ | ||
130 | /*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\ | ||
131 | 0,0,0,0,0,0,0,0, \ | ||
132 | 0,0,0x17,0x17,0x17,0x17,0x17,0x17, \ | ||
133 | _LDT(0),0x80000000, \ | ||
134 | {} \ | ||
135 | }, \ | ||
136 | } | ||
137 | |||
138 | extern struct task_struct *task[NR_TASKS]; | ||
139 | extern struct task_struct *last_task_used_math; | ||
140 | extern struct task_struct *current; | ||
141 | extern long volatile jiffies; | ||
142 | extern long startup_time; | ||
143 | |||
144 | #define CURRENT_TIME (startup_time+jiffies/HZ) | ||
145 | |||
146 | extern void add_timer(long jiffies, void (*fn)(void)); | ||
147 | extern void sleep_on(struct task_struct ** p); | ||
148 | extern void interruptible_sleep_on(struct task_struct ** p); | ||
149 | extern void wake_up(struct task_struct ** p); | ||
150 | |||
151 | /* | ||
152 | * Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall | ||
153 | * 4-TSS0, 5-LDT0, 6-TSS1 etc ... | ||
154 | */ | ||
155 | #define FIRST_TSS_ENTRY 4 | ||
156 | #define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) | ||
157 | #define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) | ||
158 | #define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) | ||
159 | #define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n))) | ||
160 | #define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n))) | ||
161 | #define str(n) \ | ||
162 | __asm__("str %%ax\n\t" \ | ||
163 | "subl %2,%%eax\n\t" \ | ||
164 | "shrl $4,%%eax" \ | ||
165 | :"=a" (n) \ | ||
166 | :"a" (0),"i" (FIRST_TSS_ENTRY<<3)) | ||
167 | /* | ||
168 | * switch_to(n) should switch tasks to task nr n, first | ||
169 | * checking that n isn't the current task, in which case it does nothing. | ||
170 | * This also clears the TS-flag if the task we switched to has used | ||
171 | * tha math co-processor latest. | ||
172 | */ | ||
173 | #define switch_to(n) {\ | ||
174 | struct {long a,b;} __tmp; \ | ||
175 | __asm__("cmpl %%ecx,current\n\t" \ | ||
176 | "je 1f\n\t" \ | ||
177 | "movw %%dx,%1\n\t" \ | ||
178 | "xchgl %%ecx,current\n\t" \ | ||
179 | "ljmp *%0\n\t" \ | ||
180 | "cmpl %%ecx,last_task_used_math\n\t" \ | ||
181 | "jne 1f\n\t" \ | ||
182 | "clts\n" \ | ||
183 | "1:" \ | ||
184 | ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ | ||
185 | "d" (_TSS(n)),"c" ((long) task[n])); \ | ||
186 | } | ||
187 | |||
188 | #define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000) | ||
189 | |||
190 | #define _set_base(addr,base) \ | ||
191 | __asm__ ("push %%edx\n\t" \ | ||
192 | "movw %%dx,%0\n\t" \ | ||
193 | "rorl $16,%%edx\n\t" \ | ||
194 | "movb %%dl,%1\n\t" \ | ||
195 | "movb %%dh,%2\n\t" \ | ||
196 | "pop %%edx" \ | ||
197 | ::"m" (*((addr)+2)), \ | ||
198 | "m" (*((addr)+4)), \ | ||
199 | "m" (*((addr)+7)), \ | ||
200 | "d" (base) \ | ||
201 | ) | ||
202 | |||
203 | #define _set_limit(addr,limit) \ | ||
204 | __asm__ ("push %%edx\n\t" \ | ||
205 | "movw %%dx,%0\n\t" \ | ||
206 | "rorl $16,%%edx\n\t" \ | ||
207 | "movb %1,%%dh\n\t" \ | ||
208 | "andb $0xf0,%%dh\n\t" \ | ||
209 | "orb %%dh,%%dl\n\t" \ | ||
210 | "movb %%dl,%1\n\t" \ | ||
211 | "pop %%edx" \ | ||
212 | ::"m" (*(addr)), \ | ||
213 | "m" (*((addr)+6)), \ | ||
214 | "d" (limit) \ | ||
215 | ) | ||
216 | |||
217 | #define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) ) | ||
218 | #define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 ) | ||
219 | |||
220 | /** | ||
221 | #define _get_base(addr) ({\ | ||
222 | unsigned long __base; \ | ||
223 | __asm__("movb %3,%%dh\n\t" \ | ||
224 | "movb %2,%%dl\n\t" \ | ||
225 | "shll $16,%%edx\n\t" \ | ||
226 | "movw %1,%%dx" \ | ||
227 | :"=d" (__base) \ | ||
228 | :"m" (*((addr)+2)), \ | ||
229 | "m" (*((addr)+4)), \ | ||
230 | "m" (*((addr)+7)) \ | ||
231 | :"memory"); \ | ||
232 | __base;}) | ||
233 | **/ | ||
234 | |||
235 | static inline unsigned long _get_base(char * addr) | ||
236 | { | ||
237 | unsigned long __base; | ||
238 | __asm__("movb %3,%%dh\n\t" | ||
239 | "movb %2,%%dl\n\t" | ||
240 | "shll $16,%%edx\n\t" | ||
241 | "movw %1,%%dx" | ||
242 | :"=&d" (__base) | ||
243 | :"m" (*((addr)+2)), | ||
244 | "m" (*((addr)+4)), | ||
245 | "m" (*((addr)+7))); | ||
246 | return __base; | ||
247 | } | ||
248 | |||
249 | #define get_base(ldt) _get_base( ((char *)&(ldt)) ) | ||
250 | |||
251 | #define get_limit(segment) ({ \ | ||
252 | unsigned long __limit; \ | ||
253 | __asm__("lsll %1,%0\n\tincl %0":"=r" (__limit):"r" (segment)); \ | ||
254 | __limit;}) | ||
255 | |||
256 | #endif | ||
diff --git a/src/include/linux/sys.h b/src/include/linux/sys.h new file mode 100644 index 0000000..c538fc1 --- /dev/null +++ b/src/include/linux/sys.h | |||
@@ -0,0 +1,86 @@ | |||
1 | extern int sys_setup(); | ||
2 | extern int sys_exit(); | ||
3 | extern int sys_fork(); | ||
4 | extern int sys_read(); | ||
5 | extern int sys_write(); | ||
6 | extern int sys_open(); | ||
7 | extern int sys_close(); | ||
8 | extern int sys_waitpid(); | ||
9 | extern int sys_creat(); | ||
10 | extern int sys_link(); | ||
11 | extern int sys_unlink(); | ||
12 | extern int sys_execve(); | ||
13 | extern int sys_chdir(); | ||
14 | extern int sys_time(); | ||
15 | extern int sys_mknod(); | ||
16 | extern int sys_chmod(); | ||
17 | extern int sys_chown(); | ||
18 | extern int sys_break(); | ||
19 | extern int sys_stat(); | ||
20 | extern int sys_lseek(); | ||
21 | extern int sys_getpid(); | ||
22 | extern int sys_mount(); | ||
23 | extern int sys_umount(); | ||
24 | extern int sys_setuid(); | ||
25 | extern int sys_getuid(); | ||
26 | extern int sys_stime(); | ||
27 | extern int sys_ptrace(); | ||
28 | extern int sys_alarm(); | ||
29 | extern int sys_fstat(); | ||
30 | extern int sys_pause(); | ||
31 | extern int sys_utime(); | ||
32 | extern int sys_stty(); | ||
33 | extern int sys_gtty(); | ||
34 | extern int sys_access(); | ||
35 | extern int sys_nice(); | ||
36 | extern int sys_ftime(); | ||
37 | extern int sys_sync(); | ||
38 | extern int sys_kill(); | ||
39 | extern int sys_rename(); | ||
40 | extern int sys_mkdir(); | ||
41 | extern int sys_rmdir(); | ||
42 | extern int sys_dup(); | ||
43 | extern int sys_pipe(); | ||
44 | extern int sys_times(); | ||
45 | extern int sys_prof(); | ||
46 | extern int sys_brk(); | ||
47 | extern int sys_setgid(); | ||
48 | extern int sys_getgid(); | ||
49 | extern int sys_signal(); | ||
50 | extern int sys_geteuid(); | ||
51 | extern int sys_getegid(); | ||
52 | extern int sys_acct(); | ||
53 | extern int sys_phys(); | ||
54 | extern int sys_lock(); | ||
55 | extern int sys_ioctl(); | ||
56 | extern int sys_fcntl(); | ||
57 | extern int sys_mpx(); | ||
58 | extern int sys_setpgid(); | ||
59 | extern int sys_ulimit(); | ||
60 | extern int sys_uname(); | ||
61 | extern int sys_umask(); | ||
62 | extern int sys_chroot(); | ||
63 | extern int sys_ustat(); | ||
64 | extern int sys_dup2(); | ||
65 | extern int sys_getppid(); | ||
66 | extern int sys_getpgrp(); | ||
67 | extern int sys_setsid(); | ||
68 | extern int sys_sigaction(); | ||
69 | extern int sys_sgetmask(); | ||
70 | extern int sys_ssetmask(); | ||
71 | extern int sys_setreuid(); | ||
72 | extern int sys_setregid(); | ||
73 | |||
74 | fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, | ||
75 | sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link, | ||
76 | sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod, | ||
77 | sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount, | ||
78 | sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm, | ||
79 | sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access, | ||
80 | sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir, | ||
81 | sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid, | ||
82 | sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys, | ||
83 | sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit, | ||
84 | sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid, | ||
85 | sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask, | ||
86 | sys_setreuid,sys_setregid }; | ||
diff --git a/src/include/linux/tty.h b/src/include/linux/tty.h new file mode 100644 index 0000000..ad846b3 --- /dev/null +++ b/src/include/linux/tty.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * 'tty.h' defines some structures used by tty_io.c and some defines. | ||
3 | * | ||
4 | * NOTE! Don't touch this without checking that nothing in rs_io.s or | ||
5 | * con_io.s breaks. Some constants are hardwired into the system (mainly | ||
6 | * offsets into 'tty_queue' | ||
7 | */ | ||
8 | |||
9 | #ifndef _TTY_H | ||
10 | #define _TTY_H | ||
11 | |||
12 | #include <termios.h> | ||
13 | |||
14 | #define TTY_BUF_SIZE 1024 | ||
15 | |||
16 | struct tty_queue { | ||
17 | unsigned long data; | ||
18 | unsigned long head; | ||
19 | unsigned long tail; | ||
20 | struct task_struct * proc_list; | ||
21 | char buf[TTY_BUF_SIZE]; | ||
22 | }; | ||
23 | |||
24 | #define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) | ||
25 | #define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) | ||
26 | #define EMPTY(a) ((a).head == (a).tail) | ||
27 | #define LEFT(a) (((a).tail-(a).head-1)&(TTY_BUF_SIZE-1)) | ||
28 | #define LAST(a) ((a).buf[(TTY_BUF_SIZE-1)&((a).head-1)]) | ||
29 | #define FULL(a) (!LEFT(a)) | ||
30 | #define CHARS(a) (((a).head-(a).tail)&(TTY_BUF_SIZE-1)) | ||
31 | #define GETCH(queue,c) \ | ||
32 | (void)({c=(queue).buf[(queue).tail];INC((queue).tail);}) | ||
33 | #define PUTCH(c,queue) \ | ||
34 | (void)({(queue).buf[(queue).head]=(c);INC((queue).head);}) | ||
35 | |||
36 | #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) | ||
37 | #define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) | ||
38 | #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) | ||
39 | #define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) | ||
40 | #define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) | ||
41 | #define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) | ||
42 | #define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) | ||
43 | #define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) | ||
44 | |||
45 | struct tty_struct { | ||
46 | struct termios termios; | ||
47 | int pgrp; | ||
48 | int stopped; | ||
49 | void (*write)(struct tty_struct * tty); | ||
50 | struct tty_queue read_q; | ||
51 | struct tty_queue write_q; | ||
52 | struct tty_queue secondary; | ||
53 | }; | ||
54 | |||
55 | extern struct tty_struct tty_table[]; | ||
56 | |||
57 | /* intr=^C quit=^| erase=del kill=^U | ||
58 | eof=^D vtime=\0 vmin=\1 sxtc=\0 | ||
59 | start=^Q stop=^S susp=^Z eol=\0 | ||
60 | reprint=^R discard=^U werase=^W lnext=^V | ||
61 | eol2=\0 | ||
62 | */ | ||
63 | #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" | ||
64 | |||
65 | void rs_init(void); | ||
66 | void con_init(void); | ||
67 | void tty_init(void); | ||
68 | |||
69 | int tty_read(unsigned c, char * buf, int n); | ||
70 | int tty_write(unsigned c, char * buf, int n); | ||
71 | |||
72 | void rs_write(struct tty_struct * tty); | ||
73 | void con_write(struct tty_struct * tty); | ||
74 | |||
75 | void copy_to_cooked(struct tty_struct * tty); | ||
76 | |||
77 | #endif | ||
diff --git a/src/include/signal.h b/src/include/signal.h new file mode 100644 index 0000000..0eea9a3 --- /dev/null +++ b/src/include/signal.h | |||
@@ -0,0 +1,68 @@ | |||
1 | #ifndef _SIGNAL_H | ||
2 | #define _SIGNAL_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | |||
6 | typedef int sig_atomic_t; | ||
7 | typedef unsigned int sigset_t; /* 32 bits */ | ||
8 | |||
9 | #define _NSIG 32 | ||
10 | #define NSIG _NSIG | ||
11 | |||
12 | #define SIGHUP 1 | ||
13 | #define SIGINT 2 | ||
14 | #define SIGQUIT 3 | ||
15 | #define SIGILL 4 | ||
16 | #define SIGTRAP 5 | ||
17 | #define SIGABRT 6 | ||
18 | #define SIGIOT 6 | ||
19 | #define SIGUNUSED 7 | ||
20 | #define SIGFPE 8 | ||
21 | #define SIGKILL 9 | ||
22 | #define SIGUSR1 10 | ||
23 | #define SIGSEGV 11 | ||
24 | #define SIGUSR2 12 | ||
25 | #define SIGPIPE 13 | ||
26 | #define SIGALRM 14 | ||
27 | #define SIGTERM 15 | ||
28 | #define SIGSTKFLT 16 | ||
29 | #define SIGCHLD 17 | ||
30 | #define SIGCONT 18 | ||
31 | #define SIGSTOP 19 | ||
32 | #define SIGTSTP 20 | ||
33 | #define SIGTTIN 21 | ||
34 | #define SIGTTOU 22 | ||
35 | |||
36 | /* Ok, I haven't implemented sigactions, but trying to keep headers POSIX */ | ||
37 | #define SA_NOCLDSTOP 1 | ||
38 | #define SA_NOMASK 0x40000000 | ||
39 | #define SA_ONESHOT 0x80000000 | ||
40 | |||
41 | #define SIG_BLOCK 0 /* for blocking signals */ | ||
42 | #define SIG_UNBLOCK 1 /* for unblocking signals */ | ||
43 | #define SIG_SETMASK 2 /* for setting the signal mask */ | ||
44 | |||
45 | #define SIG_DFL ((void (*)(int))0) /* default signal handling */ | ||
46 | #define SIG_IGN ((void (*)(int))1) /* ignore signal */ | ||
47 | |||
48 | struct sigaction { | ||
49 | void (*sa_handler)(int); | ||
50 | sigset_t sa_mask; | ||
51 | int sa_flags; | ||
52 | void (*sa_restorer)(void); | ||
53 | }; | ||
54 | |||
55 | void (*signal(int _sig, void (*_func)(int)))(int); | ||
56 | int raise(int sig); | ||
57 | int kill(pid_t pid, int sig); | ||
58 | int sigaddset(sigset_t *mask, int signo); | ||
59 | int sigdelset(sigset_t *mask, int signo); | ||
60 | int sigemptyset(sigset_t *mask); | ||
61 | int sigfillset(sigset_t *mask); | ||
62 | int sigismember(sigset_t *mask, int signo); /* 1 - is, 0 - not, -1 error */ | ||
63 | int sigpending(sigset_t *set); | ||
64 | int sigprocmask(int how, sigset_t *set, sigset_t *oldset); | ||
65 | int sigsuspend(sigset_t *sigmask); | ||
66 | int sigaction(int sig, struct sigaction *act, struct sigaction *oldact); | ||
67 | |||
68 | #endif /* _SIGNAL_H */ | ||
diff --git a/src/include/stdarg.h b/src/include/stdarg.h new file mode 100644 index 0000000..fd79ec0 --- /dev/null +++ b/src/include/stdarg.h | |||
@@ -0,0 +1,28 @@ | |||
1 | #ifndef _STDARG_H | ||
2 | #define _STDARG_H | ||
3 | |||
4 | typedef char *va_list; | ||
5 | |||
6 | /* Amount of space required in an argument list for an arg of type TYPE. | ||
7 | TYPE may alternatively be an expression whose type is used. */ | ||
8 | |||
9 | #define __va_rounded_size(TYPE) \ | ||
10 | (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) | ||
11 | |||
12 | #ifndef __sparc__ | ||
13 | #define va_start(AP, LASTARG) \ | ||
14 | (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) | ||
15 | #else | ||
16 | #define va_start(AP, LASTARG) \ | ||
17 | (__builtin_saveregs (), \ | ||
18 | AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG))) | ||
19 | #endif | ||
20 | |||
21 | void va_end (va_list); /* Defined in gnulib */ | ||
22 | #define va_end(AP) | ||
23 | |||
24 | #define va_arg(AP, TYPE) \ | ||
25 | (AP += __va_rounded_size (TYPE), \ | ||
26 | *((TYPE *) (AP - __va_rounded_size (TYPE)))) | ||
27 | |||
28 | #endif /* _STDARG_H */ | ||
diff --git a/src/include/stddef.h b/src/include/stddef.h new file mode 100644 index 0000000..97f72ff --- /dev/null +++ b/src/include/stddef.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef _STDDEF_H | ||
2 | #define _STDDEF_H | ||
3 | |||
4 | #ifndef _PTRDIFF_T | ||
5 | #define _PTRDIFF_T | ||
6 | typedef long ptrdiff_t; | ||
7 | #endif | ||
8 | |||
9 | #ifndef _SIZE_T | ||
10 | #define _SIZE_T | ||
11 | typedef unsigned long size_t; | ||
12 | #endif | ||
13 | |||
14 | #undef NULL | ||
15 | #define NULL ((void *)0) | ||
16 | |||
17 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) | ||
18 | |||
19 | #endif | ||
diff --git a/src/include/string.h b/src/include/string.h new file mode 100644 index 0000000..be98568 --- /dev/null +++ b/src/include/string.h | |||
@@ -0,0 +1,47 @@ | |||
1 | #ifndef _STRING_H_ | ||
2 | #define _STRING_H_ | ||
3 | |||
4 | #ifndef NULL | ||
5 | #define NULL ((void *) 0) | ||
6 | #endif | ||
7 | |||
8 | #ifndef _SIZE_T | ||
9 | #define _SIZE_T | ||
10 | typedef unsigned int size_t; | ||
11 | #endif | ||
12 | |||
13 | extern char * strerror(int errno); | ||
14 | |||
15 | /* | ||
16 | * This string-include defines all string functions as inline | ||
17 | * functions. Use gcc. It also assumes ds=es=data space, this should be | ||
18 | * normal. Most of the string-functions are rather heavily hand-optimized, | ||
19 | * see especially strtok,strstr,str[c]spn. They should work, but are not | ||
20 | * very easy to understand. Everything is done entirely within the register | ||
21 | * set, making the functions fast and clean. String instructions have been | ||
22 | * used through-out, making for "slightly" unclear code :-) | ||
23 | * | ||
24 | * (C) 1991 Linus Torvalds | ||
25 | */ | ||
26 | |||
27 | extern inline char * strcpy(char * dest,const char *src); | ||
28 | extern inline char * strcat(char * dest,const char * src); | ||
29 | extern inline int strcmp(const char * cs,const char * ct); | ||
30 | extern inline int strspn(const char * cs, const char * ct); | ||
31 | extern inline int strcspn(const char * cs, const char * ct); | ||
32 | extern inline char * strpbrk(const char * cs,const char * ct); | ||
33 | extern inline char * strstr(const char * cs,const char * ct); | ||
34 | extern inline int strlen(const char * s); | ||
35 | extern char * ___strtok; | ||
36 | |||
37 | extern inline char * strtok(char * s,const char * ct); | ||
38 | |||
39 | /* | ||
40 | * Changes by falcon<zhangjinw@gmail.com>, the original return value is static | ||
41 | * inline ... it can not be called by other functions in another files. | ||
42 | */ | ||
43 | |||
44 | extern inline void * memcpy(void * dest,const void * src, int n); | ||
45 | extern inline void * memmove(void * dest,const void * src, int n); | ||
46 | extern inline void * memchr(const void * cs,char c,int count); | ||
47 | #endif | ||
diff --git a/src/include/sys/stat.h b/src/include/sys/stat.h new file mode 100644 index 0000000..41c3840 --- /dev/null +++ b/src/include/sys/stat.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #ifndef _SYS_STAT_H | ||
2 | #define _SYS_STAT_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | |||
6 | struct stat { | ||
7 | dev_t st_dev; | ||
8 | ino_t st_ino; | ||
9 | umode_t st_mode; | ||
10 | nlink_t st_nlink; | ||
11 | uid_t st_uid; | ||
12 | gid_t st_gid; | ||
13 | dev_t st_rdev; | ||
14 | off_t st_size; | ||
15 | time_t st_atime; | ||
16 | time_t st_mtime; | ||
17 | time_t st_ctime; | ||
18 | }; | ||
19 | |||
20 | #define S_IFMT 00170000 | ||
21 | #define S_IFREG 0100000 | ||
22 | #define S_IFBLK 0060000 | ||
23 | #define S_IFDIR 0040000 | ||
24 | #define S_IFCHR 0020000 | ||
25 | #define S_IFIFO 0010000 | ||
26 | #define S_ISUID 0004000 | ||
27 | #define S_ISGID 0002000 | ||
28 | #define S_ISVTX 0001000 | ||
29 | |||
30 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) | ||
31 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) | ||
32 | #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) | ||
33 | #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) | ||
34 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) | ||
35 | |||
36 | #define S_IRWXU 00700 | ||
37 | #define S_IRUSR 00400 | ||
38 | #define S_IWUSR 00200 | ||
39 | #define S_IXUSR 00100 | ||
40 | |||
41 | #define S_IRWXG 00070 | ||
42 | #define S_IRGRP 00040 | ||
43 | #define S_IWGRP 00020 | ||
44 | #define S_IXGRP 00010 | ||
45 | |||
46 | #define S_IRWXO 00007 | ||
47 | #define S_IROTH 00004 | ||
48 | #define S_IWOTH 00002 | ||
49 | #define S_IXOTH 00001 | ||
50 | |||
51 | extern int chmod(const char *_path, mode_t mode); | ||
52 | extern int fstat(int fildes, struct stat *stat_buf); | ||
53 | extern int mkdir(const char *_path, mode_t mode); | ||
54 | extern int mkfifo(const char *_path, mode_t mode); | ||
55 | extern int stat(const char *filename, struct stat *stat_buf); | ||
56 | extern mode_t umask(mode_t mask); | ||
57 | |||
58 | #endif | ||
diff --git a/src/include/sys/times.h b/src/include/sys/times.h new file mode 100644 index 0000000..68d5bfb --- /dev/null +++ b/src/include/sys/times.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef _TIMES_H | ||
2 | #define _TIMES_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | |||
6 | struct tms { | ||
7 | time_t tms_utime; | ||
8 | time_t tms_stime; | ||
9 | time_t tms_cutime; | ||
10 | time_t tms_cstime; | ||
11 | }; | ||
12 | |||
13 | extern time_t times(struct tms * tp); | ||
14 | |||
15 | #endif | ||
diff --git a/src/include/sys/types.h b/src/include/sys/types.h new file mode 100644 index 0000000..557aa31 --- /dev/null +++ b/src/include/sys/types.h | |||
@@ -0,0 +1,46 @@ | |||
1 | #ifndef _SYS_TYPES_H | ||
2 | #define _SYS_TYPES_H | ||
3 | |||
4 | #ifndef _SIZE_T | ||
5 | #define _SIZE_T | ||
6 | typedef unsigned int size_t; | ||
7 | #endif | ||
8 | |||
9 | #ifndef _TIME_T | ||
10 | #define _TIME_T | ||
11 | typedef long time_t; | ||
12 | #endif | ||
13 | |||
14 | #ifndef _PTRDIFF_T | ||
15 | #define _PTRDIFF_T | ||
16 | typedef long ptrdiff_t; | ||
17 | #endif | ||
18 | |||
19 | #ifndef NULL | ||
20 | #define NULL ((void *) 0) | ||
21 | #endif | ||
22 | |||
23 | typedef int pid_t; | ||
24 | typedef unsigned short uid_t; | ||
25 | typedef unsigned char gid_t; | ||
26 | typedef unsigned short dev_t; | ||
27 | typedef unsigned short ino_t; | ||
28 | typedef unsigned short mode_t; | ||
29 | typedef unsigned short umode_t; | ||
30 | typedef unsigned char nlink_t; | ||
31 | typedef int daddr_t; | ||
32 | typedef long off_t; | ||
33 | typedef unsigned char u_char; | ||
34 | typedef unsigned short ushort; | ||
35 | |||
36 | typedef struct { int quot,rem; } div_t; | ||
37 | typedef struct { long quot,rem; } ldiv_t; | ||
38 | |||
39 | struct ustat { | ||
40 | daddr_t f_tfree; | ||
41 | ino_t f_tinode; | ||
42 | char f_fname[6]; | ||
43 | char f_fpack[6]; | ||
44 | }; | ||
45 | |||
46 | #endif | ||
diff --git a/src/include/sys/utsname.h b/src/include/sys/utsname.h new file mode 100644 index 0000000..0a1c5a0 --- /dev/null +++ b/src/include/sys/utsname.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef _SYS_UTSNAME_H | ||
2 | #define _SYS_UTSNAME_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | |||
6 | struct utsname { | ||
7 | char sysname[9]; | ||
8 | char nodename[9]; | ||
9 | char release[9]; | ||
10 | char version[9]; | ||
11 | char machine[9]; | ||
12 | }; | ||
13 | |||
14 | extern int uname(struct utsname * utsbuf); | ||
15 | |||
16 | #endif | ||
diff --git a/src/include/sys/wait.h b/src/include/sys/wait.h new file mode 100644 index 0000000..53190c2 --- /dev/null +++ b/src/include/sys/wait.h | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifndef _SYS_WAIT_H | ||
2 | #define _SYS_WAIT_H | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | |||
6 | #define _LOW(v) ( (v) & 0377) | ||
7 | #define _HIGH(v) ( ((v) >> 8) & 0377) | ||
8 | |||
9 | /* options for waitpid, WUNTRACED not supported */ | ||
10 | #define WNOHANG 1 | ||
11 | #define WUNTRACED 2 | ||
12 | |||
13 | #define WIFEXITED(s) (!((s)&0xFF) | ||
14 | #define WIFSTOPPED(s) (((s)&0xFF)==0x7F) | ||
15 | #define WEXITSTATUS(s) (((s)>>8)&0xFF) | ||
16 | #define WTERMSIG(s) ((s)&0x7F) | ||
17 | #define WSTOPSIG(s) (((s)>>8)&0xFF) | ||
18 | #define WIFSIGNALED(s) (((unsigned int)(s)-1 & 0xFFFF) < 0xFF) | ||
19 | |||
20 | pid_t wait(int *stat_loc); | ||
21 | pid_t waitpid(pid_t pid, int *stat_loc, int options); | ||
22 | |||
23 | #endif | ||
diff --git a/src/include/termios.h b/src/include/termios.h new file mode 100644 index 0000000..2b7b913 --- /dev/null +++ b/src/include/termios.h | |||
@@ -0,0 +1,228 @@ | |||
1 | #ifndef _TERMIOS_H | ||
2 | #define _TERMIOS_H | ||
3 | |||
4 | #define TTY_BUF_SIZE 1024 | ||
5 | |||
6 | /* 0x54 is just a magic number to make these relatively uniqe ('T') */ | ||
7 | |||
8 | #define TCGETS 0x5401 | ||
9 | #define TCSETS 0x5402 | ||
10 | #define TCSETSW 0x5403 | ||
11 | #define TCSETSF 0x5404 | ||
12 | #define TCGETA 0x5405 | ||
13 | #define TCSETA 0x5406 | ||
14 | #define TCSETAW 0x5407 | ||
15 | #define TCSETAF 0x5408 | ||
16 | #define TCSBRK 0x5409 | ||
17 | #define TCXONC 0x540A | ||
18 | #define TCFLSH 0x540B | ||
19 | #define TIOCEXCL 0x540C | ||
20 | #define TIOCNXCL 0x540D | ||
21 | #define TIOCSCTTY 0x540E | ||
22 | #define TIOCGPGRP 0x540F | ||
23 | #define TIOCSPGRP 0x5410 | ||
24 | #define TIOCOUTQ 0x5411 | ||
25 | #define TIOCSTI 0x5412 | ||
26 | #define TIOCGWINSZ 0x5413 | ||
27 | #define TIOCSWINSZ 0x5414 | ||
28 | #define TIOCMGET 0x5415 | ||
29 | #define TIOCMBIS 0x5416 | ||
30 | #define TIOCMBIC 0x5417 | ||
31 | #define TIOCMSET 0x5418 | ||
32 | #define TIOCGSOFTCAR 0x5419 | ||
33 | #define TIOCSSOFTCAR 0x541A | ||
34 | #define TIOCINQ 0x541B | ||
35 | |||
36 | struct winsize { | ||
37 | unsigned short ws_row; | ||
38 | unsigned short ws_col; | ||
39 | unsigned short ws_xpixel; | ||
40 | unsigned short ws_ypixel; | ||
41 | }; | ||
42 | |||
43 | #define NCC 8 | ||
44 | struct termio { | ||
45 | unsigned short c_iflag; /* input mode flags */ | ||
46 | unsigned short c_oflag; /* output mode flags */ | ||
47 | unsigned short c_cflag; /* control mode flags */ | ||
48 | unsigned short c_lflag; /* local mode flags */ | ||
49 | unsigned char c_line; /* line discipline */ | ||
50 | unsigned char c_cc[NCC]; /* control characters */ | ||
51 | }; | ||
52 | |||
53 | #define NCCS 17 | ||
54 | struct termios { | ||
55 | unsigned long c_iflag; /* input mode flags */ | ||
56 | unsigned long c_oflag; /* output mode flags */ | ||
57 | unsigned long c_cflag; /* control mode flags */ | ||
58 | unsigned long c_lflag; /* local mode flags */ | ||
59 | unsigned char c_line; /* line discipline */ | ||
60 | unsigned char c_cc[NCCS]; /* control characters */ | ||
61 | }; | ||
62 | |||
63 | /* c_cc characters */ | ||
64 | #define VINTR 0 | ||
65 | #define VQUIT 1 | ||
66 | #define VERASE 2 | ||
67 | #define VKILL 3 | ||
68 | #define VEOF 4 | ||
69 | #define VTIME 5 | ||
70 | #define VMIN 6 | ||
71 | #define VSWTC 7 | ||
72 | #define VSTART 8 | ||
73 | #define VSTOP 9 | ||
74 | #define VSUSP 10 | ||
75 | #define VEOL 11 | ||
76 | #define VREPRINT 12 | ||
77 | #define VDISCARD 13 | ||
78 | #define VWERASE 14 | ||
79 | #define VLNEXT 15 | ||
80 | #define VEOL2 16 | ||
81 | |||
82 | /* c_iflag bits */ | ||
83 | #define IGNBRK 0000001 | ||
84 | #define BRKINT 0000002 | ||
85 | #define IGNPAR 0000004 | ||
86 | #define PARMRK 0000010 | ||
87 | #define INPCK 0000020 | ||
88 | #define ISTRIP 0000040 | ||
89 | #define INLCR 0000100 | ||
90 | #define IGNCR 0000200 | ||
91 | #define ICRNL 0000400 | ||
92 | #define IUCLC 0001000 | ||
93 | #define IXON 0002000 | ||
94 | #define IXANY 0004000 | ||
95 | #define IXOFF 0010000 | ||
96 | #define IMAXBEL 0020000 | ||
97 | |||
98 | /* c_oflag bits */ | ||
99 | #define OPOST 0000001 | ||
100 | #define OLCUC 0000002 | ||
101 | #define ONLCR 0000004 | ||
102 | #define OCRNL 0000010 | ||
103 | #define ONOCR 0000020 | ||
104 | #define ONLRET 0000040 | ||
105 | #define OFILL 0000100 | ||
106 | #define OFDEL 0000200 | ||
107 | #define NLDLY 0000400 | ||
108 | #define NL0 0000000 | ||
109 | #define NL1 0000400 | ||
110 | #define CRDLY 0003000 | ||
111 | #define CR0 0000000 | ||
112 | #define CR1 0001000 | ||
113 | #define CR2 0002000 | ||
114 | #define CR3 0003000 | ||
115 | #define TABDLY 0014000 | ||
116 | #define TAB0 0000000 | ||
117 | #define TAB1 0004000 | ||
118 | #define TAB2 0010000 | ||
119 | #define TAB3 0014000 | ||
120 | #define XTABS 0014000 | ||
121 | #define BSDLY 0020000 | ||
122 | #define BS0 0000000 | ||
123 | #define BS1 0020000 | ||
124 | #define VTDLY 0040000 | ||
125 | #define VT0 0000000 | ||
126 | #define VT1 0040000 | ||
127 | #define FFDLY 0040000 | ||
128 | #define FF0 0000000 | ||
129 | #define FF1 0040000 | ||
130 | |||
131 | /* c_cflag bit meaning */ | ||
132 | #define CBAUD 0000017 | ||
133 | #define B0 0000000 /* hang up */ | ||
134 | #define B50 0000001 | ||
135 | #define B75 0000002 | ||
136 | #define B110 0000003 | ||
137 | #define B134 0000004 | ||
138 | #define B150 0000005 | ||
139 | #define B200 0000006 | ||
140 | #define B300 0000007 | ||
141 | #define B600 0000010 | ||
142 | #define B1200 0000011 | ||
143 | #define B1800 0000012 | ||
144 | #define B2400 0000013 | ||
145 | #define B4800 0000014 | ||
146 | #define B9600 0000015 | ||
147 | #define B19200 0000016 | ||
148 | #define B38400 0000017 | ||
149 | #define EXTA B19200 | ||
150 | #define EXTB B38400 | ||
151 | #define CSIZE 0000060 | ||
152 | #define CS5 0000000 | ||
153 | #define CS6 0000020 | ||
154 | #define CS7 0000040 | ||
155 | #define CS8 0000060 | ||
156 | #define CSTOPB 0000100 | ||
157 | #define CREAD 0000200 | ||
158 | #define CPARENB 0000400 | ||
159 | #define CPARODD 0001000 | ||
160 | #define HUPCL 0002000 | ||
161 | #define CLOCAL 0004000 | ||
162 | #define CIBAUD 03600000 /* input baud rate (not used) */ | ||
163 | #define CRTSCTS 020000000000 /* flow control */ | ||
164 | |||
165 | #define PARENB CPARENB | ||
166 | #define PARODD CPARODD | ||
167 | |||
168 | /* c_lflag bits */ | ||
169 | #define ISIG 0000001 | ||
170 | #define ICANON 0000002 | ||
171 | #define XCASE 0000004 | ||
172 | #define ECHO 0000010 | ||
173 | #define ECHOE 0000020 | ||
174 | #define ECHOK 0000040 | ||
175 | #define ECHONL 0000100 | ||
176 | #define NOFLSH 0000200 | ||
177 | #define TOSTOP 0000400 | ||
178 | #define ECHOCTL 0001000 | ||
179 | #define ECHOPRT 0002000 | ||
180 | #define ECHOKE 0004000 | ||
181 | #define FLUSHO 0010000 | ||
182 | #define PENDIN 0040000 | ||
183 | #define IEXTEN 0100000 | ||
184 | |||
185 | /* modem lines */ | ||
186 | #define TIOCM_LE 0x001 | ||
187 | #define TIOCM_DTR 0x002 | ||
188 | #define TIOCM_RTS 0x004 | ||
189 | #define TIOCM_ST 0x008 | ||
190 | #define TIOCM_SR 0x010 | ||
191 | #define TIOCM_CTS 0x020 | ||
192 | #define TIOCM_CAR 0x040 | ||
193 | #define TIOCM_RNG 0x080 | ||
194 | #define TIOCM_DSR 0x100 | ||
195 | #define TIOCM_CD TIOCM_CAR | ||
196 | #define TIOCM_RI TIOCM_RNG | ||
197 | |||
198 | /* tcflow() and TCXONC use these */ | ||
199 | #define TCOOFF 0 | ||
200 | #define TCOON 1 | ||
201 | #define TCIOFF 2 | ||
202 | #define TCION 3 | ||
203 | |||
204 | /* tcflush() and TCFLSH use these */ | ||
205 | #define TCIFLUSH 0 | ||
206 | #define TCOFLUSH 1 | ||
207 | #define TCIOFLUSH 2 | ||
208 | |||
209 | /* tcsetattr uses these */ | ||
210 | #define TCSANOW 0 | ||
211 | #define TCSADRAIN 1 | ||
212 | #define TCSAFLUSH 2 | ||
213 | |||
214 | typedef int speed_t; | ||
215 | |||
216 | extern speed_t cfgetispeed(struct termios *termios_p); | ||
217 | extern speed_t cfgetospeed(struct termios *termios_p); | ||
218 | extern int cfsetispeed(struct termios *termios_p, speed_t speed); | ||
219 | extern int cfsetospeed(struct termios *termios_p, speed_t speed); | ||
220 | extern int tcdrain(int fildes); | ||
221 | extern int tcflow(int fildes, int action); | ||
222 | extern int tcflush(int fildes, int queue_selector); | ||
223 | extern int tcgetattr(int fildes, struct termios *termios_p); | ||
224 | extern int tcsendbreak(int fildes, int duration); | ||
225 | extern int tcsetattr(int fildes, int optional_actions, | ||
226 | struct termios *termios_p); | ||
227 | |||
228 | #endif | ||
diff --git a/src/include/time.h b/src/include/time.h new file mode 100644 index 0000000..d0a765d --- /dev/null +++ b/src/include/time.h | |||
@@ -0,0 +1,42 @@ | |||
1 | #ifndef _TIME_H | ||
2 | #define _TIME_H | ||
3 | |||
4 | #ifndef _TIME_T | ||
5 | #define _TIME_T | ||
6 | typedef long time_t; | ||
7 | #endif | ||
8 | |||
9 | #ifndef _SIZE_T | ||
10 | #define _SIZE_T | ||
11 | typedef unsigned int size_t; | ||
12 | #endif | ||
13 | |||
14 | #define CLOCKS_PER_SEC 100 | ||
15 | |||
16 | typedef long clock_t; | ||
17 | |||
18 | struct tm { | ||
19 | int tm_sec; | ||
20 | int tm_min; | ||
21 | int tm_hour; | ||
22 | int tm_mday; | ||
23 | int tm_mon; | ||
24 | int tm_year; | ||
25 | int tm_wday; | ||
26 | int tm_yday; | ||
27 | int tm_isdst; | ||
28 | }; | ||
29 | |||
30 | clock_t clock(void); | ||
31 | time_t time(time_t * tp); | ||
32 | double difftime(time_t time2, time_t time1); | ||
33 | time_t mktime(struct tm * tp); | ||
34 | |||
35 | char * asctime(const struct tm * tp); | ||
36 | char * ctime(const time_t * tp); | ||
37 | struct tm * gmtime(const time_t *tp); | ||
38 | struct tm *localtime(const time_t * tp); | ||
39 | size_t strftime(char * s, size_t smax, const char * fmt, const struct tm * tp); | ||
40 | void tzset(void); | ||
41 | |||
42 | #endif | ||
diff --git a/src/include/unistd.h b/src/include/unistd.h new file mode 100644 index 0000000..956554a --- /dev/null +++ b/src/include/unistd.h | |||
@@ -0,0 +1,254 @@ | |||
1 | #ifndef _UNISTD_H | ||
2 | #define _UNISTD_H | ||
3 | |||
4 | /* ok, this may be a joke, but I'm working on it */ | ||
5 | #define _POSIX_VERSION 198808L | ||
6 | |||
7 | #define _POSIX_CHOWN_RESTRICTED /* only root can do a chown (I think..) */ | ||
8 | #define _POSIX_NO_TRUNC /* no pathname truncation (but see in kernel) */ | ||
9 | #define _POSIX_VDISABLE '\0' /* character to disable things like ^C */ | ||
10 | /*#define _POSIX_SAVED_IDS */ /* we'll get to this yet */ | ||
11 | /*#define _POSIX_JOB_CONTROL */ /* we aren't there quite yet. Soon hopefully */ | ||
12 | |||
13 | #define STDIN_FILENO 0 | ||
14 | #define STDOUT_FILENO 1 | ||
15 | #define STDERR_FILENO 2 | ||
16 | |||
17 | #ifndef NULL | ||
18 | #define NULL ((void *)0) | ||
19 | #endif | ||
20 | |||
21 | /* access */ | ||
22 | #define F_OK 0 | ||
23 | #define X_OK 1 | ||
24 | #define W_OK 2 | ||
25 | #define R_OK 4 | ||
26 | |||
27 | /* lseek */ | ||
28 | #define SEEK_SET 0 | ||
29 | #define SEEK_CUR 1 | ||
30 | #define SEEK_END 2 | ||
31 | |||
32 | /* _SC stands for System Configuration. We don't use them much */ | ||
33 | #define _SC_ARG_MAX 1 | ||
34 | #define _SC_CHILD_MAX 2 | ||
35 | #define _SC_CLOCKS_PER_SEC 3 | ||
36 | #define _SC_NGROUPS_MAX 4 | ||
37 | #define _SC_OPEN_MAX 5 | ||
38 | #define _SC_JOB_CONTROL 6 | ||
39 | #define _SC_SAVED_IDS 7 | ||
40 | #define _SC_VERSION 8 | ||
41 | |||
42 | /* more (possibly) configurable things - now pathnames */ | ||
43 | #define _PC_LINK_MAX 1 | ||
44 | #define _PC_MAX_CANON 2 | ||
45 | #define _PC_MAX_INPUT 3 | ||
46 | #define _PC_NAME_MAX 4 | ||
47 | #define _PC_PATH_MAX 5 | ||
48 | #define _PC_PIPE_BUF 6 | ||
49 | #define _PC_NO_TRUNC 7 | ||
50 | #define _PC_VDISABLE 8 | ||
51 | #define _PC_CHOWN_RESTRICTED 9 | ||
52 | |||
53 | #include <sys/stat.h> | ||
54 | #include <sys/times.h> | ||
55 | #include <sys/utsname.h> | ||
56 | #include <utime.h> | ||
57 | |||
58 | #ifdef __LIBRARY__ | ||
59 | |||
60 | #define __NR_setup 0 /* used only by init, to get system going */ | ||
61 | #define __NR_exit 1 | ||
62 | #define __NR_fork 2 | ||
63 | #define __NR_read 3 | ||
64 | #define __NR_write 4 | ||
65 | #define __NR_open 5 | ||
66 | #define __NR_close 6 | ||
67 | #define __NR_waitpid 7 | ||
68 | #define __NR_creat 8 | ||
69 | #define __NR_link 9 | ||
70 | #define __NR_unlink 10 | ||
71 | #define __NR_execve 11 | ||
72 | #define __NR_chdir 12 | ||
73 | #define __NR_time 13 | ||
74 | #define __NR_mknod 14 | ||
75 | #define __NR_chmod 15 | ||
76 | #define __NR_chown 16 | ||
77 | #define __NR_break 17 | ||
78 | #define __NR_stat 18 | ||
79 | #define __NR_lseek 19 | ||
80 | #define __NR_getpid 20 | ||
81 | #define __NR_mount 21 | ||
82 | #define __NR_umount 22 | ||
83 | #define __NR_setuid 23 | ||
84 | #define __NR_getuid 24 | ||
85 | #define __NR_stime 25 | ||
86 | #define __NR_ptrace 26 | ||
87 | #define __NR_alarm 27 | ||
88 | #define __NR_fstat 28 | ||
89 | #define __NR_pause 29 | ||
90 | #define __NR_utime 30 | ||
91 | #define __NR_stty 31 | ||
92 | #define __NR_gtty 32 | ||
93 | #define __NR_access 33 | ||
94 | #define __NR_nice 34 | ||
95 | #define __NR_ftime 35 | ||
96 | #define __NR_sync 36 | ||
97 | #define __NR_kill 37 | ||
98 | #define __NR_rename 38 | ||
99 | #define __NR_mkdir 39 | ||
100 | #define __NR_rmdir 40 | ||
101 | #define __NR_dup 41 | ||
102 | #define __NR_pipe 42 | ||
103 | #define __NR_times 43 | ||
104 | #define __NR_prof 44 | ||
105 | #define __NR_brk 45 | ||
106 | #define __NR_setgid 46 | ||
107 | #define __NR_getgid 47 | ||
108 | #define __NR_signal 48 | ||
109 | #define __NR_geteuid 49 | ||
110 | #define __NR_getegid 50 | ||
111 | #define __NR_acct 51 | ||
112 | #define __NR_phys 52 | ||
113 | #define __NR_lock 53 | ||
114 | #define __NR_ioctl 54 | ||
115 | #define __NR_fcntl 55 | ||
116 | #define __NR_mpx 56 | ||
117 | #define __NR_setpgid 57 | ||
118 | #define __NR_ulimit 58 | ||
119 | #define __NR_uname 59 | ||
120 | #define __NR_umask 60 | ||
121 | #define __NR_chroot 61 | ||
122 | #define __NR_ustat 62 | ||
123 | #define __NR_dup2 63 | ||
124 | #define __NR_getppid 64 | ||
125 | #define __NR_getpgrp 65 | ||
126 | #define __NR_setsid 66 | ||
127 | #define __NR_sigaction 67 | ||
128 | #define __NR_sgetmask 68 | ||
129 | #define __NR_ssetmask 69 | ||
130 | #define __NR_setreuid 70 | ||
131 | #define __NR_setregid 71 | ||
132 | |||
133 | #define _syscall0(type,name) \ | ||
134 | type name(void) \ | ||
135 | { \ | ||
136 | long __res; \ | ||
137 | __asm__ volatile ("int $0x80" \ | ||
138 | : "=a" (__res) \ | ||
139 | : "0" (__NR_##name)); \ | ||
140 | if (__res >= 0) \ | ||
141 | return (type) __res; \ | ||
142 | errno = -__res; \ | ||
143 | return -1; \ | ||
144 | } | ||
145 | |||
146 | #define _syscall1(type,name,atype,a) \ | ||
147 | type name(atype a) \ | ||
148 | { \ | ||
149 | long __res; \ | ||
150 | __asm__ volatile ("int $0x80" \ | ||
151 | : "=a" (__res) \ | ||
152 | : "0" (__NR_##name),"b" ((long)(a))); \ | ||
153 | if (__res >= 0) \ | ||
154 | return (type) __res; \ | ||
155 | errno = -__res; \ | ||
156 | return -1; \ | ||
157 | } | ||
158 | |||
159 | #define _syscall2(type,name,atype,a,btype,b) \ | ||
160 | type name(atype a,btype b) \ | ||
161 | { \ | ||
162 | long __res; \ | ||
163 | __asm__ volatile ("int $0x80" \ | ||
164 | : "=a" (__res) \ | ||
165 | : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \ | ||
166 | if (__res >= 0) \ | ||
167 | return (type) __res; \ | ||
168 | errno = -__res; \ | ||
169 | return -1; \ | ||
170 | } | ||
171 | |||
172 | #define _syscall3(type,name,atype,a,btype,b,ctype,c) \ | ||
173 | type name(atype a,btype b,ctype c) \ | ||
174 | { \ | ||
175 | long __res; \ | ||
176 | __asm__ volatile ("int $0x80" \ | ||
177 | : "=a" (__res) \ | ||
178 | : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \ | ||
179 | if (__res>=0) \ | ||
180 | return (type) __res; \ | ||
181 | errno=-__res; \ | ||
182 | return -1; \ | ||
183 | } | ||
184 | |||
185 | #endif /* __LIBRARY__ */ | ||
186 | |||
187 | extern int errno; | ||
188 | |||
189 | int access(const char * filename, mode_t mode); | ||
190 | int acct(const char * filename); | ||
191 | int alarm(int sec); | ||
192 | int brk(void * end_data_segment); | ||
193 | void * sbrk(ptrdiff_t increment); | ||
194 | int chdir(const char * filename); | ||
195 | int chmod(const char * filename, mode_t mode); | ||
196 | int chown(const char * filename, uid_t owner, gid_t group); | ||
197 | int chroot(const char * filename); | ||
198 | int close(int fildes); | ||
199 | int creat(const char * filename, mode_t mode); | ||
200 | int dup(int fildes); | ||
201 | int execve(const char * filename, char ** argv, char ** envp); | ||
202 | int execv(const char * pathname, char ** argv); | ||
203 | int execvp(const char * file, char ** argv); | ||
204 | int execl(const char * pathname, char * arg0, ...); | ||
205 | int execlp(const char * file, char * arg0, ...); | ||
206 | int execle(const char * pathname, char * arg0, ...); | ||
207 | //volatile void exit(int status); | ||
208 | void _exit(int status); | ||
209 | //volatile void _exit(int status); | ||
210 | int fcntl(int fildes, int cmd, ...); | ||
211 | static int fork(void); | ||
212 | int getpid(void); | ||
213 | int getuid(void); | ||
214 | int geteuid(void); | ||
215 | int getgid(void); | ||
216 | int getegid(void); | ||
217 | int ioctl(int fildes, int cmd, ...); | ||
218 | int kill(pid_t pid, int signal); | ||
219 | int link(const char * filename1, const char * filename2); | ||
220 | int lseek(int fildes, off_t offset, int origin); | ||
221 | int mknod(const char * filename, mode_t mode, dev_t dev); | ||
222 | int mount(const char * specialfile, const char * dir, int rwflag); | ||
223 | int nice(int val); | ||
224 | int open(const char * filename, int flag, ...); | ||
225 | static int pause(void); | ||
226 | int pipe(int * fildes); | ||
227 | int read(int fildes, char * buf, off_t count); | ||
228 | int setpgrp(void); | ||
229 | int setpgid(pid_t pid,pid_t pgid); | ||
230 | int setuid(uid_t uid); | ||
231 | int setgid(gid_t gid); | ||
232 | void (*signal(int sig, void (*fn)(int)))(int); | ||
233 | int stat(const char * filename, struct stat * stat_buf); | ||
234 | int fstat(int fildes, struct stat * stat_buf); | ||
235 | int stime(time_t * tptr); | ||
236 | static int sync(void); | ||
237 | time_t time(time_t * tloc); | ||
238 | time_t times(struct tms * tbuf); | ||
239 | int ulimit(int cmd, long limit); | ||
240 | mode_t umask(mode_t mask); | ||
241 | int umount(const char * specialfile); | ||
242 | int uname(struct utsname * name); | ||
243 | int unlink(const char * filename); | ||
244 | int ustat(dev_t dev, struct ustat * ubuf); | ||
245 | int utime(const char * filename, struct utimbuf * times); | ||
246 | pid_t waitpid(pid_t pid,int * wait_stat,int options); | ||
247 | pid_t wait(int * wait_stat); | ||
248 | int write(int fildes, const char * buf, off_t count); | ||
249 | int dup2(int oldfd, int newfd); | ||
250 | int getppid(void); | ||
251 | pid_t getpgrp(void); | ||
252 | pid_t setsid(void); | ||
253 | |||
254 | #endif | ||
diff --git a/src/include/utime.h b/src/include/utime.h new file mode 100644 index 0000000..83f07c7 --- /dev/null +++ b/src/include/utime.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef _UTIME_H | ||
2 | #define _UTIME_H | ||
3 | |||
4 | #include <sys/types.h> /* I know - shouldn't do this, but .. */ | ||
5 | |||
6 | struct utimbuf { | ||
7 | time_t actime; | ||
8 | time_t modtime; | ||
9 | }; | ||
10 | |||
11 | extern int utime(const char *filename, struct utimbuf *times); | ||
12 | |||
13 | #endif | ||
diff --git a/src/init/main.c b/src/init/main.c new file mode 100644 index 0000000..db103f4 --- /dev/null +++ b/src/init/main.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * linux/init/main.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | #include <time.h> | ||
10 | |||
11 | /* | ||
12 | * we need this inline - forking from kernel space will result | ||
13 | * in NO COPY ON WRITE (!!!), until an execve is executed. This | ||
14 | * is no problem, but for the stack. This is handled by not letting | ||
15 | * main() use the stack at all after fork(). Thus, no function | ||
16 | * calls - which means inline code for fork too, as otherwise we | ||
17 | * would use the stack upon exit from 'fork()'. | ||
18 | * | ||
19 | * Actually only pause and fork are needed inline, so that there | ||
20 | * won't be any messing with the stack from main(), but we define | ||
21 | * some others too. | ||
22 | */ | ||
23 | static inline fork(void) __attribute__((always_inline)); | ||
24 | static inline pause(void) __attribute__((always_inline)); | ||
25 | static inline _syscall0(int,fork) | ||
26 | static inline _syscall0(int,pause) | ||
27 | static inline _syscall1(int,setup,void *,BIOS) | ||
28 | static inline _syscall0(int,sync) | ||
29 | |||
30 | #include <linux/tty.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/head.h> | ||
33 | #include <asm/system.h> | ||
34 | #include <asm/io.h> | ||
35 | |||
36 | #include <stddef.h> | ||
37 | #include <stdarg.h> | ||
38 | #include <unistd.h> | ||
39 | #include <fcntl.h> | ||
40 | #include <sys/types.h> | ||
41 | |||
42 | #include <linux/fs.h> | ||
43 | |||
44 | static char printbuf[1024]; | ||
45 | |||
46 | extern int vsprintf(); | ||
47 | extern void init(void); | ||
48 | extern void blk_dev_init(void); | ||
49 | extern void chr_dev_init(void); | ||
50 | extern void hd_init(void); | ||
51 | extern void floppy_init(void); | ||
52 | extern void mem_init(long start, long end); | ||
53 | extern long rd_init(long mem_start, int length); | ||
54 | extern long kernel_mktime(struct tm * tm); | ||
55 | extern long startup_time; | ||
56 | |||
57 | /* | ||
58 | * This is set up by the setup-routine at boot-time | ||
59 | */ | ||
60 | #define EXT_MEM_K (*(unsigned short *)0x90002) | ||
61 | #define DRIVE_INFO (*(struct drive_info *)0x90080) | ||
62 | #define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) | ||
63 | |||
64 | /* | ||
65 | * Yeah, yeah, it's ugly, but I cannot find how to do this correctly | ||
66 | * and this seems to work. I anybody has more info on the real-time | ||
67 | * clock I'd be interested. Most of this was trial and error, and some | ||
68 | * bios-listing reading. Urghh. | ||
69 | */ | ||
70 | |||
71 | #define CMOS_READ(addr) ({ \ | ||
72 | outb_p(0x80|addr,0x70); \ | ||
73 | inb_p(0x71); \ | ||
74 | }) | ||
75 | |||
76 | #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) | ||
77 | |||
78 | static void time_init(void) | ||
79 | { | ||
80 | struct tm time; | ||
81 | |||
82 | do { | ||
83 | time.tm_sec = CMOS_READ(0); | ||
84 | time.tm_min = CMOS_READ(2); | ||
85 | time.tm_hour = CMOS_READ(4); | ||
86 | time.tm_mday = CMOS_READ(7); | ||
87 | time.tm_mon = CMOS_READ(8); | ||
88 | time.tm_year = CMOS_READ(9); | ||
89 | } while (time.tm_sec != CMOS_READ(0)); | ||
90 | BCD_TO_BIN(time.tm_sec); | ||
91 | BCD_TO_BIN(time.tm_min); | ||
92 | BCD_TO_BIN(time.tm_hour); | ||
93 | BCD_TO_BIN(time.tm_mday); | ||
94 | BCD_TO_BIN(time.tm_mon); | ||
95 | BCD_TO_BIN(time.tm_year); | ||
96 | time.tm_mon--; | ||
97 | startup_time = kernel_mktime(&time); | ||
98 | } | ||
99 | |||
100 | static long memory_end = 0; | ||
101 | static long buffer_memory_end = 0; | ||
102 | static long main_memory_start = 0; | ||
103 | |||
104 | struct drive_info { char dummy[32]; } drive_info; | ||
105 | |||
106 | void main(void) /* This really IS void, no error here. */ | ||
107 | { /* The startup routine assumes (well, ...) this */ | ||
108 | /* | ||
109 | * Interrupts are still disabled. Do necessary setups, then | ||
110 | * enable them | ||
111 | */ | ||
112 | |||
113 | ROOT_DEV = ORIG_ROOT_DEV; | ||
114 | drive_info = DRIVE_INFO; | ||
115 | memory_end = (1<<20) + (EXT_MEM_K<<10); | ||
116 | memory_end &= 0xfffff000; | ||
117 | if (memory_end > 16*1024*1024) | ||
118 | memory_end = 16*1024*1024; | ||
119 | if (memory_end > 12*1024*1024) | ||
120 | buffer_memory_end = 4*1024*1024; | ||
121 | else if (memory_end > 6*1024*1024) | ||
122 | buffer_memory_end = 2*1024*1024; | ||
123 | else | ||
124 | buffer_memory_end = 1*1024*1024; | ||
125 | main_memory_start = buffer_memory_end; | ||
126 | #ifdef RAMDISK | ||
127 | main_memory_start += rd_init(main_memory_start, RAMDISK*1024); | ||
128 | #endif | ||
129 | mem_init(main_memory_start,memory_end); | ||
130 | trap_init(); | ||
131 | blk_dev_init(); | ||
132 | chr_dev_init(); | ||
133 | tty_init(); | ||
134 | time_init(); | ||
135 | sched_init(); | ||
136 | buffer_init(buffer_memory_end); | ||
137 | hd_init(); | ||
138 | floppy_init(); | ||
139 | sti(); | ||
140 | move_to_user_mode(); | ||
141 | if (!fork()) { /* we count on this going ok */ | ||
142 | init(); | ||
143 | } | ||
144 | /* | ||
145 | * NOTE!! For any other task 'pause()' would mean we have to get a | ||
146 | * signal to awaken, but task0 is the sole exception (see 'schedule()') | ||
147 | * as task 0 gets activated at every idle moment (when no other tasks | ||
148 | * can run). For task0 'pause()' just means we go check if some other | ||
149 | * task can run, and if not we return here. | ||
150 | */ | ||
151 | for(;;) pause(); | ||
152 | } | ||
153 | |||
154 | static int printf(const char *fmt, ...) | ||
155 | { | ||
156 | va_list args; | ||
157 | int i; | ||
158 | |||
159 | va_start(args, fmt); | ||
160 | write(1,printbuf,i=vsprintf(printbuf, fmt, args)); | ||
161 | va_end(args); | ||
162 | return i; | ||
163 | } | ||
164 | |||
165 | static char * argv_rc[] = { "/bin/bash", NULL }; | ||
166 | static char * envp_rc[] = { "HOME=/", NULL }; | ||
167 | |||
168 | static char * argv[] = { "-/bin/bash",NULL }; | ||
169 | static char * envp[] = { "HOME=/usr/root", NULL }; | ||
170 | |||
171 | void init(void) | ||
172 | { | ||
173 | int pid,i; | ||
174 | |||
175 | setup((void *) &drive_info); | ||
176 | (void) open("/dev/tty0",O_RDWR,0); | ||
177 | (void) dup(0); | ||
178 | (void) dup(0); | ||
179 | printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS, | ||
180 | NR_BUFFERS*BLOCK_SIZE); | ||
181 | printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); | ||
182 | if (!(pid=fork())) { | ||
183 | close(0); | ||
184 | if (open("/etc/rc",O_RDONLY,0)) | ||
185 | _exit(1); | ||
186 | execve("/bin/bash",argv_rc,envp_rc); | ||
187 | _exit(2); | ||
188 | } | ||
189 | if (pid>0) | ||
190 | while (pid != wait(&i)) | ||
191 | /* nothing */; | ||
192 | while (1) { | ||
193 | if ((pid=fork())<0) { | ||
194 | printf("Fork failed in init\r\n"); | ||
195 | continue; | ||
196 | } | ||
197 | if (!pid) { | ||
198 | close(0);close(1);close(2); | ||
199 | setsid(); | ||
200 | (void) open("/dev/tty0",O_RDWR,0); | ||
201 | (void) dup(0); | ||
202 | (void) dup(0); | ||
203 | _exit(execve("/bin/bash",argv,envp)); | ||
204 | } | ||
205 | while (1) | ||
206 | if (pid == wait(&i)) | ||
207 | break; | ||
208 | printf("\n\rchild %d died with code %04x\n\r",pid,i); | ||
209 | sync(); | ||
210 | } | ||
211 | _exit(0); /* NOTE! _exit, not exit() */ | ||
212 | } | ||
diff --git a/src/kernel/Makefile b/src/kernel/Makefile new file mode 100644 index 0000000..aa6b3d7 --- /dev/null +++ b/src/kernel/Makefile | |||
@@ -0,0 +1,87 @@ | |||
1 | # | ||
2 | # Makefile for the FREAX-kernel. | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | include ../Makefile.header | ||
10 | |||
11 | LDFLAGS += -r | ||
12 | |||
13 | # NOTE!: do not try to add -On to CFLAGS with gcc4.x, which will optimize the | ||
14 | # memcpy function a lot to let the kernel not work, for fixing this problem, | ||
15 | # please refer to glibc and rewrite the memcpy in include/string.h, or just not | ||
16 | # use any -On options with gcc 4.x when compiling it. in fact, we only can not | ||
17 | # use -On with gcc4.x to compile fork.c, but after that you need to isolate the | ||
18 | # compling procedure of it, it's not good too. for playing with linux-0.11, we | ||
19 | # just have fun, have no much concerning about the performance. | ||
20 | |||
21 | CFLAGS += -I../include | ||
22 | |||
23 | CPP += -I../include | ||
24 | |||
25 | .c.s: | ||
26 | @$(CC) $(CFLAGS) \ | ||
27 | -S -o $*.s $< | ||
28 | .s.o: | ||
29 | @$(AS) -o $*.o $< | ||
30 | .c.o: | ||
31 | @$(CC) $(CFLAGS) \ | ||
32 | -c -o $*.o $< | ||
33 | |||
34 | OBJS = sched.o system_call.o traps.o asm.o fork.o \ | ||
35 | panic.o printk.o vsprintf.o sys.o exit.o \ | ||
36 | signal.o mktime.o | ||
37 | |||
38 | kernel.o: $(OBJS) | ||
39 | @$(LD) $(LDFLAGS) -o kernel.o $(OBJS) | ||
40 | @sync | ||
41 | |||
42 | clean: | ||
43 | @rm -f core *.o *.a tmp_make keyboard.s | ||
44 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
45 | @for i in chr_drv blk_drv math; do make clean -C $$i; done | ||
46 | |||
47 | dep: | ||
48 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
49 | @(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ | ||
50 | $(CPP) -M $$i;done) >> tmp_make | ||
51 | @cp tmp_make Makefile | ||
52 | @for i in chr_drv blk_drv; do make dep -C $$i; done | ||
53 | |||
54 | ### Dependencies: | ||
55 | exit.s exit.o: exit.c ../include/errno.h ../include/signal.h \ | ||
56 | ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \ | ||
57 | ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ | ||
58 | ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \ | ||
59 | ../include/asm/segment.h | ||
60 | fork.s fork.o: fork.c ../include/errno.h ../include/linux/sched.h \ | ||
61 | ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ | ||
62 | ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ | ||
63 | ../include/asm/segment.h ../include/asm/system.h | ||
64 | mktime.s mktime.o: mktime.c ../include/time.h | ||
65 | panic.s panic.o: panic.c ../include/linux/kernel.h ../include/linux/sched.h \ | ||
66 | ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ | ||
67 | ../include/linux/mm.h ../include/signal.h | ||
68 | printk.s printk.o: printk.c ../include/stdarg.h ../include/stddef.h \ | ||
69 | ../include/linux/kernel.h | ||
70 | sched.s sched.o: sched.c ../include/linux/sched.h ../include/linux/head.h \ | ||
71 | ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ | ||
72 | ../include/signal.h ../include/linux/kernel.h ../include/linux/sys.h \ | ||
73 | ../include/linux/fdreg.h ../include/asm/system.h ../include/asm/io.h \ | ||
74 | ../include/asm/segment.h | ||
75 | signal.s signal.o: signal.c ../include/linux/sched.h ../include/linux/head.h \ | ||
76 | ../include/linux/fs.h ../include/sys/types.h ../include/linux/mm.h \ | ||
77 | ../include/signal.h ../include/linux/kernel.h ../include/asm/segment.h | ||
78 | sys.s sys.o: sys.c ../include/errno.h ../include/linux/sched.h \ | ||
79 | ../include/linux/head.h ../include/linux/fs.h ../include/sys/types.h \ | ||
80 | ../include/linux/mm.h ../include/signal.h ../include/linux/tty.h \ | ||
81 | ../include/termios.h ../include/linux/kernel.h ../include/asm/segment.h \ | ||
82 | ../include/sys/times.h ../include/sys/utsname.h | ||
83 | traps.s traps.o: traps.c ../include/string.h ../include/linux/head.h \ | ||
84 | ../include/linux/sched.h ../include/linux/fs.h ../include/sys/types.h \ | ||
85 | ../include/linux/mm.h ../include/signal.h ../include/linux/kernel.h \ | ||
86 | ../include/asm/system.h ../include/asm/segment.h ../include/asm/io.h | ||
87 | vsprintf.s vsprintf.o: vsprintf.c ../include/stdarg.h ../include/string.h | ||
diff --git a/src/kernel/asm.s b/src/kernel/asm.s new file mode 100644 index 0000000..1022817 --- /dev/null +++ b/src/kernel/asm.s | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * linux/kernel/asm.s | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * asm.s contains the low-level code for most hardware faults. | ||
9 | * page_exception is handled by the mm, so that isn't here. This | ||
10 | * file also handles (hopefully) fpu-exceptions due to TS-bit, as | ||
11 | * the fpu must be properly saved/resored. This hasn't been tested. | ||
12 | */ | ||
13 | |||
14 | .globl divide_error,debug,nmi,int3,overflow,bounds,invalid_op | ||
15 | .globl double_fault,coprocessor_segment_overrun | ||
16 | .globl invalid_TSS,segment_not_present,stack_segment | ||
17 | .globl general_protection,coprocessor_error,irq13,reserved | ||
18 | |||
19 | divide_error: | ||
20 | pushl $do_divide_error | ||
21 | no_error_code: | ||
22 | xchgl %eax,(%esp) | ||
23 | pushl %ebx | ||
24 | pushl %ecx | ||
25 | pushl %edx | ||
26 | pushl %edi | ||
27 | pushl %esi | ||
28 | pushl %ebp | ||
29 | push %ds | ||
30 | push %es | ||
31 | push %fs | ||
32 | pushl $0 # "error code" | ||
33 | lea 44(%esp),%edx | ||
34 | pushl %edx | ||
35 | movl $0x10,%edx | ||
36 | mov %dx,%ds | ||
37 | mov %dx,%es | ||
38 | mov %dx,%fs | ||
39 | call *%eax | ||
40 | addl $8,%esp | ||
41 | pop %fs | ||
42 | pop %es | ||
43 | pop %ds | ||
44 | popl %ebp | ||
45 | popl %esi | ||
46 | popl %edi | ||
47 | popl %edx | ||
48 | popl %ecx | ||
49 | popl %ebx | ||
50 | popl %eax | ||
51 | iret | ||
52 | |||
53 | debug: | ||
54 | pushl $do_int3 # _do_debug | ||
55 | jmp no_error_code | ||
56 | |||
57 | nmi: | ||
58 | pushl $do_nmi | ||
59 | jmp no_error_code | ||
60 | |||
61 | int3: | ||
62 | pushl $do_int3 | ||
63 | jmp no_error_code | ||
64 | |||
65 | overflow: | ||
66 | pushl $do_overflow | ||
67 | jmp no_error_code | ||
68 | |||
69 | bounds: | ||
70 | pushl $do_bounds | ||
71 | jmp no_error_code | ||
72 | |||
73 | invalid_op: | ||
74 | pushl $do_invalid_op | ||
75 | jmp no_error_code | ||
76 | |||
77 | coprocessor_segment_overrun: | ||
78 | pushl $do_coprocessor_segment_overrun | ||
79 | jmp no_error_code | ||
80 | |||
81 | reserved: | ||
82 | pushl $do_reserved | ||
83 | jmp no_error_code | ||
84 | |||
85 | irq13: | ||
86 | pushl %eax | ||
87 | xorb %al,%al | ||
88 | outb %al,$0xF0 | ||
89 | movb $0x20,%al | ||
90 | outb %al,$0x20 | ||
91 | jmp 1f | ||
92 | 1: jmp 1f | ||
93 | 1: outb %al,$0xA0 | ||
94 | popl %eax | ||
95 | jmp coprocessor_error | ||
96 | |||
97 | double_fault: | ||
98 | pushl $do_double_fault | ||
99 | error_code: | ||
100 | xchgl %eax,4(%esp) # error code <-> %eax | ||
101 | xchgl %ebx,(%esp) # &function <-> %ebx | ||
102 | pushl %ecx | ||
103 | pushl %edx | ||
104 | pushl %edi | ||
105 | pushl %esi | ||
106 | pushl %ebp | ||
107 | push %ds | ||
108 | push %es | ||
109 | push %fs | ||
110 | pushl %eax # error code | ||
111 | lea 44(%esp),%eax # offset | ||
112 | pushl %eax | ||
113 | movl $0x10,%eax | ||
114 | mov %ax,%ds | ||
115 | mov %ax,%es | ||
116 | mov %ax,%fs | ||
117 | call *%ebx | ||
118 | addl $8,%esp | ||
119 | pop %fs | ||
120 | pop %es | ||
121 | pop %ds | ||
122 | popl %ebp | ||
123 | popl %esi | ||
124 | popl %edi | ||
125 | popl %edx | ||
126 | popl %ecx | ||
127 | popl %ebx | ||
128 | popl %eax | ||
129 | iret | ||
130 | |||
131 | invalid_TSS: | ||
132 | pushl $do_invalid_TSS | ||
133 | jmp error_code | ||
134 | |||
135 | segment_not_present: | ||
136 | pushl $do_segment_not_present | ||
137 | jmp error_code | ||
138 | |||
139 | stack_segment: | ||
140 | pushl $do_stack_segment | ||
141 | jmp error_code | ||
142 | |||
143 | general_protection: | ||
144 | pushl $do_general_protection | ||
145 | jmp error_code | ||
146 | |||
diff --git a/src/kernel/blk_drv/Makefile b/src/kernel/blk_drv/Makefile new file mode 100644 index 0000000..766d2fd --- /dev/null +++ b/src/kernel/blk_drv/Makefile | |||
@@ -0,0 +1,62 @@ | |||
1 | # | ||
2 | # Makefile for the FREAX-kernel block device drivers. | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | include ../../Makefile.header | ||
10 | |||
11 | CFLAGS += -I../../include | ||
12 | CPP += -I../../include | ||
13 | |||
14 | .c.s: | ||
15 | @$(CC) $(CFLAGS) \ | ||
16 | -S -o $*.s $< | ||
17 | .s.o: | ||
18 | @$(AS) -o $*.o $< | ||
19 | .c.o: | ||
20 | @$(CC) $(CFLAGS) \ | ||
21 | -c -o $*.o $< | ||
22 | |||
23 | OBJS = ll_rw_blk.o floppy.o hd.o ramdisk.o | ||
24 | |||
25 | blk_drv.a: $(OBJS) | ||
26 | @$(AR) rcs blk_drv.a $(OBJS) | ||
27 | @sync | ||
28 | |||
29 | clean: | ||
30 | @rm -f core *.o *.a tmp_make | ||
31 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
32 | |||
33 | dep: | ||
34 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
35 | @(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ | ||
36 | $(CPP) -M $$i;done) >> tmp_make | ||
37 | @cp tmp_make Makefile | ||
38 | |||
39 | ### Dependencies: | ||
40 | floppy.s floppy.o: floppy.c ../../include/linux/sched.h ../../include/linux/head.h \ | ||
41 | ../../include/linux/fs.h ../../include/sys/types.h \ | ||
42 | ../../include/linux/mm.h ../../include/signal.h \ | ||
43 | ../../include/linux/kernel.h ../../include/linux/fdreg.h \ | ||
44 | ../../include/asm/system.h ../../include/asm/io.h \ | ||
45 | ../../include/asm/segment.h blk.h | ||
46 | hd.s hd.o: hd.c ../../include/linux/config.h ../../include/linux/sched.h \ | ||
47 | ../../include/linux/head.h ../../include/linux/fs.h \ | ||
48 | ../../include/sys/types.h ../../include/linux/mm.h \ | ||
49 | ../../include/signal.h ../../include/linux/kernel.h \ | ||
50 | ../../include/linux/hdreg.h ../../include/asm/system.h \ | ||
51 | ../../include/asm/io.h ../../include/asm/segment.h blk.h | ||
52 | ll_rw_blk.s ll_rw_blk.o: ll_rw_blk.c ../../include/errno.h \ | ||
53 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
54 | ../../include/linux/fs.h ../../include/sys/types.h \ | ||
55 | ../../include/linux/mm.h ../../include/signal.h \ | ||
56 | ../../include/linux/kernel.h ../../include/asm/system.h blk.h | ||
57 | ramdisk.s ramdisk.o: ramdisk.c ../../include/string.h ../../include/linux/config.h \ | ||
58 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
59 | ../../include/linux/fs.h ../../include/sys/types.h \ | ||
60 | ../../include/linux/mm.h ../../include/signal.h \ | ||
61 | ../../include/linux/kernel.h ../../include/asm/system.h \ | ||
62 | ../../include/asm/segment.h ../../include/asm/memory.h blk.h | ||
diff --git a/src/kernel/blk_drv/blk.h b/src/kernel/blk_drv/blk.h new file mode 100644 index 0000000..b272173 --- /dev/null +++ b/src/kernel/blk_drv/blk.h | |||
@@ -0,0 +1,140 @@ | |||
1 | #ifndef _BLK_H | ||
2 | #define _BLK_H | ||
3 | |||
4 | #define NR_BLK_DEV 7 | ||
5 | /* | ||
6 | * NR_REQUEST is the number of entries in the request-queue. | ||
7 | * NOTE that writes may use only the low 2/3 of these: reads | ||
8 | * take precedence. | ||
9 | * | ||
10 | * 32 seems to be a reasonable number: enough to get some benefit | ||
11 | * from the elevator-mechanism, but not so much as to lock a lot of | ||
12 | * buffers when they are in the queue. 64 seems to be too many (easily | ||
13 | * long pauses in reading when heavy writing/syncing is going on) | ||
14 | */ | ||
15 | #define NR_REQUEST 32 | ||
16 | |||
17 | /* | ||
18 | * Ok, this is an expanded form so that we can use the same | ||
19 | * request for paging requests when that is implemented. In | ||
20 | * paging, 'bh' is NULL, and 'waiting' is used to wait for | ||
21 | * read/write completion. | ||
22 | */ | ||
23 | struct request { | ||
24 | int dev; /* -1 if no request */ | ||
25 | int cmd; /* READ or WRITE */ | ||
26 | int errors; | ||
27 | unsigned long sector; | ||
28 | unsigned long nr_sectors; | ||
29 | char * buffer; | ||
30 | struct task_struct * waiting; | ||
31 | struct buffer_head * bh; | ||
32 | struct request * next; | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * This is used in the elevator algorithm: Note that | ||
37 | * reads always go before writes. This is natural: reads | ||
38 | * are much more time-critical than writes. | ||
39 | */ | ||
40 | #define IN_ORDER(s1,s2) \ | ||
41 | ((s1)->cmd<(s2)->cmd || ((s1)->cmd==(s2)->cmd && \ | ||
42 | ((s1)->dev < (s2)->dev || ((s1)->dev == (s2)->dev && \ | ||
43 | (s1)->sector < (s2)->sector)))) | ||
44 | |||
45 | struct blk_dev_struct { | ||
46 | void (*request_fn)(void); | ||
47 | struct request * current_request; | ||
48 | }; | ||
49 | |||
50 | extern struct blk_dev_struct blk_dev[NR_BLK_DEV]; | ||
51 | extern struct request request[NR_REQUEST]; | ||
52 | extern struct task_struct * wait_for_request; | ||
53 | |||
54 | #ifdef MAJOR_NR | ||
55 | |||
56 | /* | ||
57 | * Add entries as needed. Currently the only block devices | ||
58 | * supported are hard-disks and floppies. | ||
59 | */ | ||
60 | |||
61 | #if (MAJOR_NR == 1) | ||
62 | /* ram disk */ | ||
63 | #define DEVICE_NAME "ramdisk" | ||
64 | #define DEVICE_REQUEST do_rd_request | ||
65 | #define DEVICE_NR(device) ((device) & 7) | ||
66 | #define DEVICE_ON(device) | ||
67 | #define DEVICE_OFF(device) | ||
68 | |||
69 | #elif (MAJOR_NR == 2) | ||
70 | /* floppy */ | ||
71 | #define DEVICE_NAME "floppy" | ||
72 | #define DEVICE_INTR do_floppy | ||
73 | #define DEVICE_REQUEST do_fd_request | ||
74 | #define DEVICE_NR(device) ((device) & 3) | ||
75 | #define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) | ||
76 | #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) | ||
77 | |||
78 | #elif (MAJOR_NR == 3) | ||
79 | /* harddisk */ | ||
80 | #define DEVICE_NAME "harddisk" | ||
81 | #define DEVICE_INTR do_hd | ||
82 | #define DEVICE_REQUEST do_hd_request | ||
83 | #define DEVICE_NR(device) (MINOR(device)/5) | ||
84 | #define DEVICE_ON(device) | ||
85 | #define DEVICE_OFF(device) | ||
86 | |||
87 | #else | ||
88 | /* unknown blk device */ | ||
89 | #error "unknown blk device" | ||
90 | |||
91 | #endif | ||
92 | |||
93 | #define CURRENT (blk_dev[MAJOR_NR].current_request) | ||
94 | #define CURRENT_DEV DEVICE_NR(CURRENT->dev) | ||
95 | |||
96 | #ifdef DEVICE_INTR | ||
97 | void (*DEVICE_INTR)(void) = NULL; | ||
98 | #endif | ||
99 | static void (DEVICE_REQUEST)(void); | ||
100 | |||
101 | static inline void unlock_buffer(struct buffer_head * bh) | ||
102 | { | ||
103 | if (!bh->b_lock) | ||
104 | printk(DEVICE_NAME ": free buffer being unlocked\n"); | ||
105 | bh->b_lock=0; | ||
106 | wake_up(&bh->b_wait); | ||
107 | } | ||
108 | |||
109 | static inline void end_request(int uptodate) | ||
110 | { | ||
111 | DEVICE_OFF(CURRENT->dev); | ||
112 | if (CURRENT->bh) { | ||
113 | CURRENT->bh->b_uptodate = uptodate; | ||
114 | unlock_buffer(CURRENT->bh); | ||
115 | } | ||
116 | if (!uptodate) { | ||
117 | printk(DEVICE_NAME " I/O error\n\r"); | ||
118 | printk("dev %04x, block %d\n\r",CURRENT->dev, | ||
119 | CURRENT->bh->b_blocknr); | ||
120 | } | ||
121 | wake_up(&CURRENT->waiting); | ||
122 | wake_up(&wait_for_request); | ||
123 | CURRENT->dev = -1; | ||
124 | CURRENT = CURRENT->next; | ||
125 | } | ||
126 | |||
127 | #define INIT_REQUEST \ | ||
128 | repeat: \ | ||
129 | if (!CURRENT) \ | ||
130 | return; \ | ||
131 | if (MAJOR(CURRENT->dev) != MAJOR_NR) \ | ||
132 | panic(DEVICE_NAME ": request list destroyed"); \ | ||
133 | if (CURRENT->bh) { \ | ||
134 | if (!CURRENT->bh->b_lock) \ | ||
135 | panic(DEVICE_NAME ": block not locked"); \ | ||
136 | } | ||
137 | |||
138 | #endif | ||
139 | |||
140 | #endif | ||
diff --git a/src/kernel/blk_drv/floppy.c b/src/kernel/blk_drv/floppy.c new file mode 100644 index 0000000..f497906 --- /dev/null +++ b/src/kernel/blk_drv/floppy.c | |||
@@ -0,0 +1,462 @@ | |||
1 | /* | ||
2 | * linux/kernel/floppy.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 02.12.91 - Changed to static variables to indicate need for reset | ||
9 | * and recalibrate. This makes some things easier (output_byte reset | ||
10 | * checking etc), and means less interrupt jumping in case of errors, | ||
11 | * so the code is hopefully easier to understand. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * This file is certainly a mess. I've tried my best to get it working, | ||
16 | * but I don't like programming floppies, and I have only one anyway. | ||
17 | * Urgel. I should check for more errors, and do more graceful error | ||
18 | * recovery. Seems there are problems with several drives. I've tried to | ||
19 | * correct them. No promises. | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * As with hd.c, all routines within this file can (and will) be called | ||
24 | * by interrupts, so extreme caution is needed. A hardware interrupt | ||
25 | * handler may not sleep, or a kernel panic will happen. Thus I cannot | ||
26 | * call "floppy-on" directly, but have to set a special timer interrupt | ||
27 | * etc. | ||
28 | * | ||
29 | * Also, I'm not certain this works on more than 1 floppy. Bugs may | ||
30 | * abund. | ||
31 | */ | ||
32 | |||
33 | #include <linux/sched.h> | ||
34 | #include <linux/fs.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/fdreg.h> | ||
37 | #include <asm/system.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <asm/segment.h> | ||
40 | |||
41 | #define MAJOR_NR 2 | ||
42 | #include "blk.h" | ||
43 | |||
44 | static int recalibrate = 0; | ||
45 | static int reset = 0; | ||
46 | static int seek = 0; | ||
47 | |||
48 | extern unsigned char current_DOR; | ||
49 | |||
50 | #define immoutb_p(val,port) \ | ||
51 | __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port)) | ||
52 | |||
53 | #define TYPE(x) ((x)>>2) | ||
54 | #define DRIVE(x) ((x)&0x03) | ||
55 | /* | ||
56 | * Note that MAX_ERRORS=8 doesn't imply that we retry every bad read | ||
57 | * max 8 times - some types of errors increase the errorcount by 2, | ||
58 | * so we might actually retry only 5-6 times before giving up. | ||
59 | */ | ||
60 | #define MAX_ERRORS 8 | ||
61 | |||
62 | /* | ||
63 | * globals used by 'result()' | ||
64 | */ | ||
65 | #define MAX_REPLIES 7 | ||
66 | static unsigned char reply_buffer[MAX_REPLIES]; | ||
67 | #define ST0 (reply_buffer[0]) | ||
68 | #define ST1 (reply_buffer[1]) | ||
69 | #define ST2 (reply_buffer[2]) | ||
70 | #define ST3 (reply_buffer[3]) | ||
71 | |||
72 | /* | ||
73 | * This struct defines the different floppy types. Unlike minix | ||
74 | * linux doesn't have a "search for right type"-type, as the code | ||
75 | * for that is convoluted and weird. I've got enough problems with | ||
76 | * this driver as it is. | ||
77 | * | ||
78 | * The 'stretch' tells if the tracks need to be boubled for some | ||
79 | * types (ie 360kB diskette in 1.2MB drive etc). Others should | ||
80 | * be self-explanatory. | ||
81 | */ | ||
82 | static struct floppy_struct { | ||
83 | unsigned int size, sect, head, track, stretch; | ||
84 | unsigned char gap,rate,spec1; | ||
85 | } floppy_type[] = { | ||
86 | { 0, 0,0, 0,0,0x00,0x00,0x00 }, /* no testing */ | ||
87 | { 720, 9,2,40,0,0x2A,0x02,0xDF }, /* 360kB PC diskettes */ | ||
88 | { 2400,15,2,80,0,0x1B,0x00,0xDF }, /* 1.2 MB AT-diskettes */ | ||
89 | { 720, 9,2,40,1,0x2A,0x02,0xDF }, /* 360kB in 720kB drive */ | ||
90 | { 1440, 9,2,80,0,0x2A,0x02,0xDF }, /* 3.5" 720kB diskette */ | ||
91 | { 720, 9,2,40,1,0x23,0x01,0xDF }, /* 360kB in 1.2MB drive */ | ||
92 | { 1440, 9,2,80,0,0x23,0x01,0xDF }, /* 720kB in 1.2MB drive */ | ||
93 | { 2880,18,2,80,0,0x1B,0x00,0xCF }, /* 1.44MB diskette */ | ||
94 | }; | ||
95 | /* | ||
96 | * Rate is 0 for 500kb/s, 2 for 300kbps, 1 for 250kbps | ||
97 | * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), | ||
98 | * H is head unload time (1=16ms, 2=32ms, etc) | ||
99 | * | ||
100 | * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc) | ||
101 | * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). | ||
102 | */ | ||
103 | |||
104 | extern void floppy_interrupt(void); | ||
105 | extern char tmp_floppy_area[1024]; | ||
106 | |||
107 | /* | ||
108 | * These are global variables, as that's the easiest way to give | ||
109 | * information to interrupts. They are the data used for the current | ||
110 | * request. | ||
111 | */ | ||
112 | static int cur_spec1 = -1; | ||
113 | static int cur_rate = -1; | ||
114 | static struct floppy_struct * floppy = floppy_type; | ||
115 | static unsigned char current_drive = 0; | ||
116 | static unsigned char sector = 0; | ||
117 | static unsigned char head = 0; | ||
118 | static unsigned char track = 0; | ||
119 | static unsigned char seek_track = 0; | ||
120 | static unsigned char current_track = 255; | ||
121 | static unsigned char command = 0; | ||
122 | unsigned char selected = 0; | ||
123 | struct task_struct * wait_on_floppy_select = NULL; | ||
124 | |||
125 | void floppy_deselect(unsigned int nr) | ||
126 | { | ||
127 | if (nr != (current_DOR & 3)) | ||
128 | printk("floppy_deselect: drive not selected\n\r"); | ||
129 | selected = 0; | ||
130 | wake_up(&wait_on_floppy_select); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * floppy-change is never called from an interrupt, so we can relax a bit | ||
135 | * here, sleep etc. Note that floppy-on tries to set current_DOR to point | ||
136 | * to the desired drive, but it will probably not survive the sleep if | ||
137 | * several floppies are used at the same time: thus the loop. | ||
138 | */ | ||
139 | int floppy_change(unsigned int nr) | ||
140 | { | ||
141 | repeat: | ||
142 | floppy_on(nr); | ||
143 | while ((current_DOR & 3) != nr && selected) | ||
144 | interruptible_sleep_on(&wait_on_floppy_select); | ||
145 | if ((current_DOR & 3) != nr) | ||
146 | goto repeat; | ||
147 | if (inb(FD_DIR) & 0x80) { | ||
148 | floppy_off(nr); | ||
149 | return 1; | ||
150 | } | ||
151 | floppy_off(nr); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | #define copy_buffer(from,to) \ | ||
156 | __asm__("cld ; rep ; movsl" \ | ||
157 | ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \ | ||
158 | ) | ||
159 | |||
160 | static void setup_DMA(void) | ||
161 | { | ||
162 | long addr = (long) CURRENT->buffer; | ||
163 | |||
164 | cli(); | ||
165 | if (addr >= 0x100000) { | ||
166 | addr = (long) tmp_floppy_area; | ||
167 | if (command == FD_WRITE) | ||
168 | copy_buffer(CURRENT->buffer,tmp_floppy_area); | ||
169 | } | ||
170 | /* mask DMA 2 */ | ||
171 | immoutb_p(4|2,10); | ||
172 | /* output command byte. I don't know why, but everyone (minix, */ | ||
173 | /* sanches & canton) output this twice, first to 12 then to 11 */ | ||
174 | __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t" | ||
175 | "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:":: | ||
176 | "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE))); | ||
177 | /* 8 low bits of addr */ | ||
178 | immoutb_p(addr,4); | ||
179 | addr >>= 8; | ||
180 | /* bits 8-15 of addr */ | ||
181 | immoutb_p(addr,4); | ||
182 | addr >>= 8; | ||
183 | /* bits 16-19 of addr */ | ||
184 | immoutb_p(addr,0x81); | ||
185 | /* low 8 bits of count-1 (1024-1=0x3ff) */ | ||
186 | immoutb_p(0xff,5); | ||
187 | /* high 8 bits of count-1 */ | ||
188 | immoutb_p(3,5); | ||
189 | /* activate DMA 2 */ | ||
190 | immoutb_p(0|2,10); | ||
191 | sti(); | ||
192 | } | ||
193 | |||
194 | static void output_byte(char byte) | ||
195 | { | ||
196 | int counter; | ||
197 | unsigned char status; | ||
198 | |||
199 | if (reset) | ||
200 | return; | ||
201 | for(counter = 0 ; counter < 10000 ; counter++) { | ||
202 | status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR); | ||
203 | if (status == STATUS_READY) { | ||
204 | outb(byte,FD_DATA); | ||
205 | return; | ||
206 | } | ||
207 | } | ||
208 | reset = 1; | ||
209 | printk("Unable to send byte to FDC\n\r"); | ||
210 | } | ||
211 | |||
212 | static int result(void) | ||
213 | { | ||
214 | int i = 0, counter, status; | ||
215 | |||
216 | if (reset) | ||
217 | return -1; | ||
218 | for (counter = 0 ; counter < 10000 ; counter++) { | ||
219 | status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); | ||
220 | if (status == STATUS_READY) | ||
221 | return i; | ||
222 | if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { | ||
223 | if (i >= MAX_REPLIES) | ||
224 | break; | ||
225 | reply_buffer[i++] = inb_p(FD_DATA); | ||
226 | } | ||
227 | } | ||
228 | reset = 1; | ||
229 | printk("Getstatus times out\n\r"); | ||
230 | return -1; | ||
231 | } | ||
232 | |||
233 | static void bad_flp_intr(void) | ||
234 | { | ||
235 | CURRENT->errors++; | ||
236 | if (CURRENT->errors > MAX_ERRORS) { | ||
237 | floppy_deselect(current_drive); | ||
238 | end_request(0); | ||
239 | } | ||
240 | if (CURRENT->errors > MAX_ERRORS/2) | ||
241 | reset = 1; | ||
242 | else | ||
243 | recalibrate = 1; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Ok, this interrupt is called after a DMA read/write has succeeded, | ||
248 | * so we check the results, and copy any buffers. | ||
249 | */ | ||
250 | static void rw_interrupt(void) | ||
251 | { | ||
252 | if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) { | ||
253 | if (ST1 & 0x02) { | ||
254 | printk("Drive %d is write protected\n\r",current_drive); | ||
255 | floppy_deselect(current_drive); | ||
256 | end_request(0); | ||
257 | } else | ||
258 | bad_flp_intr(); | ||
259 | do_fd_request(); | ||
260 | return; | ||
261 | } | ||
262 | if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= 0x100000) | ||
263 | copy_buffer(tmp_floppy_area,CURRENT->buffer); | ||
264 | floppy_deselect(current_drive); | ||
265 | end_request(1); | ||
266 | do_fd_request(); | ||
267 | } | ||
268 | |||
269 | static inline void setup_rw_floppy(void) | ||
270 | { | ||
271 | setup_DMA(); | ||
272 | do_floppy = rw_interrupt; | ||
273 | output_byte(command); | ||
274 | output_byte(head<<2 | current_drive); | ||
275 | output_byte(track); | ||
276 | output_byte(head); | ||
277 | output_byte(sector); | ||
278 | output_byte(2); /* sector size = 512 */ | ||
279 | output_byte(floppy->sect); | ||
280 | output_byte(floppy->gap); | ||
281 | output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ | ||
282 | if (reset) | ||
283 | do_fd_request(); | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * This is the routine called after every seek (or recalibrate) interrupt | ||
288 | * from the floppy controller. Note that the "unexpected interrupt" routine | ||
289 | * also does a recalibrate, but doesn't come here. | ||
290 | */ | ||
291 | static void seek_interrupt(void) | ||
292 | { | ||
293 | /* sense drive status */ | ||
294 | output_byte(FD_SENSEI); | ||
295 | if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { | ||
296 | bad_flp_intr(); | ||
297 | do_fd_request(); | ||
298 | return; | ||
299 | } | ||
300 | current_track = ST1; | ||
301 | setup_rw_floppy(); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * This routine is called when everything should be correctly set up | ||
306 | * for the transfer (ie floppy motor is on and the correct floppy is | ||
307 | * selected). | ||
308 | */ | ||
309 | static void transfer(void) | ||
310 | { | ||
311 | if (cur_spec1 != floppy->spec1) { | ||
312 | cur_spec1 = floppy->spec1; | ||
313 | output_byte(FD_SPECIFY); | ||
314 | output_byte(cur_spec1); /* hut etc */ | ||
315 | output_byte(6); /* Head load time =6ms, DMA */ | ||
316 | } | ||
317 | if (cur_rate != floppy->rate) | ||
318 | outb_p(cur_rate = floppy->rate,FD_DCR); | ||
319 | if (reset) { | ||
320 | do_fd_request(); | ||
321 | return; | ||
322 | } | ||
323 | if (!seek) { | ||
324 | setup_rw_floppy(); | ||
325 | return; | ||
326 | } | ||
327 | do_floppy = seek_interrupt; | ||
328 | if (seek_track) { | ||
329 | output_byte(FD_SEEK); | ||
330 | output_byte(head<<2 | current_drive); | ||
331 | output_byte(seek_track); | ||
332 | } else { | ||
333 | output_byte(FD_RECALIBRATE); | ||
334 | output_byte(head<<2 | current_drive); | ||
335 | } | ||
336 | if (reset) | ||
337 | do_fd_request(); | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * Special case - used after a unexpected interrupt (or reset) | ||
342 | */ | ||
343 | static void recal_interrupt(void) | ||
344 | { | ||
345 | output_byte(FD_SENSEI); | ||
346 | if (result()!=2 || (ST0 & 0xE0) == 0x60) | ||
347 | reset = 1; | ||
348 | else | ||
349 | recalibrate = 0; | ||
350 | do_fd_request(); | ||
351 | } | ||
352 | |||
353 | void unexpected_floppy_interrupt(void) | ||
354 | { | ||
355 | output_byte(FD_SENSEI); | ||
356 | if (result()!=2 || (ST0 & 0xE0) == 0x60) | ||
357 | reset = 1; | ||
358 | else | ||
359 | recalibrate = 1; | ||
360 | } | ||
361 | |||
362 | static void recalibrate_floppy(void) | ||
363 | { | ||
364 | recalibrate = 0; | ||
365 | current_track = 0; | ||
366 | do_floppy = recal_interrupt; | ||
367 | output_byte(FD_RECALIBRATE); | ||
368 | output_byte(head<<2 | current_drive); | ||
369 | if (reset) | ||
370 | do_fd_request(); | ||
371 | } | ||
372 | |||
373 | static void reset_interrupt(void) | ||
374 | { | ||
375 | output_byte(FD_SENSEI); | ||
376 | (void) result(); | ||
377 | output_byte(FD_SPECIFY); | ||
378 | output_byte(cur_spec1); /* hut etc */ | ||
379 | output_byte(6); /* Head load time =6ms, DMA */ | ||
380 | do_fd_request(); | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * reset is done by pulling bit 2 of DOR low for a while. | ||
385 | */ | ||
386 | static void reset_floppy(void) | ||
387 | { | ||
388 | int i; | ||
389 | |||
390 | reset = 0; | ||
391 | cur_spec1 = -1; | ||
392 | cur_rate = -1; | ||
393 | recalibrate = 1; | ||
394 | printk("Reset-floppy called\n\r"); | ||
395 | cli(); | ||
396 | do_floppy = reset_interrupt; | ||
397 | outb_p(current_DOR & ~0x04,FD_DOR); | ||
398 | for (i=0 ; i<100 ; i++) | ||
399 | __asm__("nop"); | ||
400 | outb(current_DOR,FD_DOR); | ||
401 | sti(); | ||
402 | } | ||
403 | |||
404 | static void floppy_on_interrupt(void) | ||
405 | { | ||
406 | /* We cannot do a floppy-select, as that might sleep. We just force it */ | ||
407 | selected = 1; | ||
408 | if (current_drive != (current_DOR & 3)) { | ||
409 | current_DOR &= 0xFC; | ||
410 | current_DOR |= current_drive; | ||
411 | outb(current_DOR,FD_DOR); | ||
412 | add_timer(2,&transfer); | ||
413 | } else | ||
414 | transfer(); | ||
415 | } | ||
416 | |||
417 | void do_fd_request(void) | ||
418 | { | ||
419 | unsigned int block; | ||
420 | |||
421 | seek = 0; | ||
422 | if (reset) { | ||
423 | reset_floppy(); | ||
424 | return; | ||
425 | } | ||
426 | if (recalibrate) { | ||
427 | recalibrate_floppy(); | ||
428 | return; | ||
429 | } | ||
430 | INIT_REQUEST; | ||
431 | floppy = (MINOR(CURRENT->dev)>>2) + floppy_type; | ||
432 | if (current_drive != CURRENT_DEV) | ||
433 | seek = 1; | ||
434 | current_drive = CURRENT_DEV; | ||
435 | block = CURRENT->sector; | ||
436 | if (block+2 > floppy->size) { | ||
437 | end_request(0); | ||
438 | goto repeat; | ||
439 | } | ||
440 | sector = block % floppy->sect; | ||
441 | block /= floppy->sect; | ||
442 | head = block % floppy->head; | ||
443 | track = block / floppy->head; | ||
444 | seek_track = track << floppy->stretch; | ||
445 | if (seek_track != current_track) | ||
446 | seek = 1; | ||
447 | sector++; | ||
448 | if (CURRENT->cmd == READ) | ||
449 | command = FD_READ; | ||
450 | else if (CURRENT->cmd == WRITE) | ||
451 | command = FD_WRITE; | ||
452 | else | ||
453 | panic("do_fd_request: unknown command"); | ||
454 | add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt); | ||
455 | } | ||
456 | |||
457 | void floppy_init(void) | ||
458 | { | ||
459 | blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; | ||
460 | set_trap_gate(0x26,&floppy_interrupt); | ||
461 | outb(inb_p(0x21)&~0x40,0x21); | ||
462 | } | ||
diff --git a/src/kernel/blk_drv/hd.c b/src/kernel/blk_drv/hd.c new file mode 100644 index 0000000..d5e1aa9 --- /dev/null +++ b/src/kernel/blk_drv/hd.c | |||
@@ -0,0 +1,349 @@ | |||
1 | /* | ||
2 | * linux/kernel/hd.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This is the low-level hd interrupt support. It traverses the | ||
9 | * request-list, using interrupts to jump between functions. As | ||
10 | * all the functions are called within interrupts, we may not | ||
11 | * sleep. Special care is recommended. | ||
12 | * | ||
13 | * modified by Drew Eckhardt to check nr of hd's from the CMOS. | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/hdreg.h> | ||
21 | #include <asm/system.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/segment.h> | ||
24 | |||
25 | #define MAJOR_NR 3 | ||
26 | #include "blk.h" | ||
27 | |||
28 | #define CMOS_READ(addr) ({ \ | ||
29 | outb_p(0x80|addr,0x70); \ | ||
30 | inb_p(0x71); \ | ||
31 | }) | ||
32 | |||
33 | /* Max read/write errors/sector */ | ||
34 | #define MAX_ERRORS 7 | ||
35 | #define MAX_HD 2 | ||
36 | |||
37 | static void recal_intr(void); | ||
38 | |||
39 | static int recalibrate = 0; | ||
40 | static int reset = 0; | ||
41 | |||
42 | /* | ||
43 | * This struct defines the HD's and their types. | ||
44 | */ | ||
45 | struct hd_i_struct { | ||
46 | int head,sect,cyl,wpcom,lzone,ctl; | ||
47 | }; | ||
48 | #ifdef HD_TYPE | ||
49 | struct hd_i_struct hd_info[] = { HD_TYPE }; | ||
50 | #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct))) | ||
51 | #else | ||
52 | struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; | ||
53 | static int NR_HD = 0; | ||
54 | #endif | ||
55 | |||
56 | static struct hd_struct { | ||
57 | long start_sect; | ||
58 | long nr_sects; | ||
59 | } hd[5*MAX_HD]={{0,0},}; | ||
60 | |||
61 | #define port_read(port,buf,nr) \ | ||
62 | __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr)) | ||
63 | |||
64 | #define port_write(port,buf,nr) \ | ||
65 | __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr)) | ||
66 | |||
67 | extern void hd_interrupt(void); | ||
68 | extern void rd_load(void); | ||
69 | |||
70 | /* This may be used only once, enforced by 'static int callable' */ | ||
71 | int sys_setup(void * BIOS) | ||
72 | { | ||
73 | static int callable = 1; | ||
74 | int i,drive; | ||
75 | unsigned char cmos_disks; | ||
76 | struct partition *p; | ||
77 | struct buffer_head * bh; | ||
78 | |||
79 | if (!callable) | ||
80 | return -1; | ||
81 | callable = 0; | ||
82 | #ifndef HD_TYPE | ||
83 | for (drive=0 ; drive<2 ; drive++) { | ||
84 | hd_info[drive].cyl = *(unsigned short *) BIOS; | ||
85 | hd_info[drive].head = *(unsigned char *) (2+BIOS); | ||
86 | hd_info[drive].wpcom = *(unsigned short *) (5+BIOS); | ||
87 | hd_info[drive].ctl = *(unsigned char *) (8+BIOS); | ||
88 | hd_info[drive].lzone = *(unsigned short *) (12+BIOS); | ||
89 | hd_info[drive].sect = *(unsigned char *) (14+BIOS); | ||
90 | BIOS += 16; | ||
91 | } | ||
92 | if (hd_info[1].cyl) | ||
93 | NR_HD=2; | ||
94 | else | ||
95 | NR_HD=1; | ||
96 | #endif | ||
97 | for (i=0 ; i<NR_HD ; i++) { | ||
98 | hd[i*5].start_sect = 0; | ||
99 | hd[i*5].nr_sects = hd_info[i].head* | ||
100 | hd_info[i].sect*hd_info[i].cyl; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | We querry CMOS about hard disks : it could be that | ||
105 | we have a SCSI/ESDI/etc controller that is BIOS | ||
106 | compatable with ST-506, and thus showing up in our | ||
107 | BIOS table, but not register compatable, and therefore | ||
108 | not present in CMOS. | ||
109 | |||
110 | Furthurmore, we will assume that our ST-506 drives | ||
111 | <if any> are the primary drives in the system, and | ||
112 | the ones reflected as drive 1 or 2. | ||
113 | |||
114 | The first drive is stored in the high nibble of CMOS | ||
115 | byte 0x12, the second in the low nibble. This will be | ||
116 | either a 4 bit drive type or 0xf indicating use byte 0x19 | ||
117 | for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. | ||
118 | |||
119 | Needless to say, a non-zero value means we have | ||
120 | an AT controller hard disk for that drive. | ||
121 | |||
122 | |||
123 | */ | ||
124 | |||
125 | if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) | ||
126 | if (cmos_disks & 0x0f) | ||
127 | NR_HD = 2; | ||
128 | else | ||
129 | NR_HD = 1; | ||
130 | else | ||
131 | NR_HD = 0; | ||
132 | for (i = NR_HD ; i < 2 ; i++) { | ||
133 | hd[i*5].start_sect = 0; | ||
134 | hd[i*5].nr_sects = 0; | ||
135 | } | ||
136 | for (drive=0 ; drive<NR_HD ; drive++) { | ||
137 | if (!(bh = bread(0x300 + drive*5,0))) { | ||
138 | printk("Unable to read partition table of drive %d\n\r", | ||
139 | drive); | ||
140 | panic(""); | ||
141 | } | ||
142 | if (bh->b_data[510] != 0x55 || (unsigned char) | ||
143 | bh->b_data[511] != 0xAA) { | ||
144 | printk("Bad partition table on drive %d\n\r",drive); | ||
145 | panic(""); | ||
146 | } | ||
147 | p = 0x1BE + (void *)bh->b_data; | ||
148 | for (i=1;i<5;i++,p++) { | ||
149 | hd[i+5*drive].start_sect = p->start_sect; | ||
150 | hd[i+5*drive].nr_sects = p->nr_sects; | ||
151 | } | ||
152 | brelse(bh); | ||
153 | } | ||
154 | if (NR_HD) | ||
155 | printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":""); | ||
156 | rd_load(); | ||
157 | mount_root(); | ||
158 | return (0); | ||
159 | } | ||
160 | |||
161 | static int controller_ready(void) | ||
162 | { | ||
163 | int retries=100000; | ||
164 | |||
165 | while (--retries && (inb_p(HD_STATUS)&0x80)); | ||
166 | return (retries); | ||
167 | } | ||
168 | |||
169 | static int win_result(void) | ||
170 | { | ||
171 | int i=inb_p(HD_STATUS); | ||
172 | |||
173 | if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) | ||
174 | == (READY_STAT | SEEK_STAT)) | ||
175 | return(0); /* ok */ | ||
176 | if (i&1) i=inb(HD_ERROR); | ||
177 | return (1); | ||
178 | } | ||
179 | |||
180 | static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect, | ||
181 | unsigned int head,unsigned int cyl,unsigned int cmd, | ||
182 | void (*intr_addr)(void)) | ||
183 | { | ||
184 | register int port asm("dx"); | ||
185 | |||
186 | if (drive>1 || head>15) | ||
187 | panic("Trying to write bad sector"); | ||
188 | if (!controller_ready()) | ||
189 | panic("HD controller not ready"); | ||
190 | do_hd = intr_addr; | ||
191 | outb_p(hd_info[drive].ctl,HD_CMD); | ||
192 | port=HD_DATA; | ||
193 | outb_p(hd_info[drive].wpcom>>2,++port); | ||
194 | outb_p(nsect,++port); | ||
195 | outb_p(sect,++port); | ||
196 | outb_p(cyl,++port); | ||
197 | outb_p(cyl>>8,++port); | ||
198 | outb_p(0xA0|(drive<<4)|head,++port); | ||
199 | outb(cmd,++port); | ||
200 | } | ||
201 | |||
202 | static int drive_busy(void) | ||
203 | { | ||
204 | unsigned int i; | ||
205 | |||
206 | for (i = 0; i < 10000; i++) | ||
207 | if (READY_STAT == (inb_p(HD_STATUS) & (BUSY_STAT|READY_STAT))) | ||
208 | break; | ||
209 | i = inb(HD_STATUS); | ||
210 | i &= BUSY_STAT | READY_STAT | SEEK_STAT; | ||
211 | if (i == (READY_STAT | SEEK_STAT)) | ||
212 | return(0); | ||
213 | printk("HD controller times out\n\r"); | ||
214 | return(1); | ||
215 | } | ||
216 | |||
217 | static void reset_controller(void) | ||
218 | { | ||
219 | int i; | ||
220 | |||
221 | outb(4,HD_CMD); | ||
222 | for(i = 0; i < 100; i++) nop(); | ||
223 | outb(hd_info[0].ctl & 0x0f ,HD_CMD); | ||
224 | if (drive_busy()) | ||
225 | printk("HD-controller still busy\n\r"); | ||
226 | if ((i = inb(HD_ERROR)) != 1) | ||
227 | printk("HD-controller reset failed: %02x\n\r",i); | ||
228 | } | ||
229 | |||
230 | static void reset_hd(int nr) | ||
231 | { | ||
232 | reset_controller(); | ||
233 | hd_out(nr,hd_info[nr].sect,hd_info[nr].sect,hd_info[nr].head-1, | ||
234 | hd_info[nr].cyl,WIN_SPECIFY,&recal_intr); | ||
235 | } | ||
236 | |||
237 | void unexpected_hd_interrupt(void) | ||
238 | { | ||
239 | printk("Unexpected HD interrupt\n\r"); | ||
240 | } | ||
241 | |||
242 | static void bad_rw_intr(void) | ||
243 | { | ||
244 | if (++CURRENT->errors >= MAX_ERRORS) | ||
245 | end_request(0); | ||
246 | if (CURRENT->errors > MAX_ERRORS/2) | ||
247 | reset = 1; | ||
248 | } | ||
249 | |||
250 | static void read_intr(void) | ||
251 | { | ||
252 | if (win_result()) { | ||
253 | bad_rw_intr(); | ||
254 | do_hd_request(); | ||
255 | return; | ||
256 | } | ||
257 | port_read(HD_DATA,CURRENT->buffer,256); | ||
258 | CURRENT->errors = 0; | ||
259 | CURRENT->buffer += 512; | ||
260 | CURRENT->sector++; | ||
261 | if (--CURRENT->nr_sectors) { | ||
262 | do_hd = &read_intr; | ||
263 | return; | ||
264 | } | ||
265 | end_request(1); | ||
266 | do_hd_request(); | ||
267 | } | ||
268 | |||
269 | static void write_intr(void) | ||
270 | { | ||
271 | if (win_result()) { | ||
272 | bad_rw_intr(); | ||
273 | do_hd_request(); | ||
274 | return; | ||
275 | } | ||
276 | if (--CURRENT->nr_sectors) { | ||
277 | CURRENT->sector++; | ||
278 | CURRENT->buffer += 512; | ||
279 | do_hd = &write_intr; | ||
280 | port_write(HD_DATA,CURRENT->buffer,256); | ||
281 | return; | ||
282 | } | ||
283 | end_request(1); | ||
284 | do_hd_request(); | ||
285 | } | ||
286 | |||
287 | static void recal_intr(void) | ||
288 | { | ||
289 | if (win_result()) | ||
290 | bad_rw_intr(); | ||
291 | do_hd_request(); | ||
292 | } | ||
293 | |||
294 | void do_hd_request(void) | ||
295 | { | ||
296 | int i,r = 0; | ||
297 | unsigned int block,dev; | ||
298 | unsigned int sec,head,cyl; | ||
299 | unsigned int nsect; | ||
300 | |||
301 | INIT_REQUEST; | ||
302 | dev = MINOR(CURRENT->dev); | ||
303 | block = CURRENT->sector; | ||
304 | if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) { | ||
305 | end_request(0); | ||
306 | goto repeat; | ||
307 | } | ||
308 | block += hd[dev].start_sect; | ||
309 | dev /= 5; | ||
310 | __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0), | ||
311 | "r" (hd_info[dev].sect)); | ||
312 | __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0), | ||
313 | "r" (hd_info[dev].head)); | ||
314 | sec++; | ||
315 | nsect = CURRENT->nr_sectors; | ||
316 | if (reset) { | ||
317 | reset = 0; | ||
318 | recalibrate = 1; | ||
319 | reset_hd(CURRENT_DEV); | ||
320 | return; | ||
321 | } | ||
322 | if (recalibrate) { | ||
323 | recalibrate = 0; | ||
324 | hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0, | ||
325 | WIN_RESTORE,&recal_intr); | ||
326 | return; | ||
327 | } | ||
328 | if (CURRENT->cmd == WRITE) { | ||
329 | hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); | ||
330 | for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) | ||
331 | /* nothing */ ; | ||
332 | if (!r) { | ||
333 | bad_rw_intr(); | ||
334 | goto repeat; | ||
335 | } | ||
336 | port_write(HD_DATA,CURRENT->buffer,256); | ||
337 | } else if (CURRENT->cmd == READ) { | ||
338 | hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); | ||
339 | } else | ||
340 | panic("unknown hd-command"); | ||
341 | } | ||
342 | |||
343 | void hd_init(void) | ||
344 | { | ||
345 | blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; | ||
346 | set_intr_gate(0x2E,&hd_interrupt); | ||
347 | outb_p(inb_p(0x21)&0xfb,0x21); | ||
348 | outb(inb_p(0xA1)&0xbf,0xA1); | ||
349 | } | ||
diff --git a/src/kernel/blk_drv/ll_rw_blk.c b/src/kernel/blk_drv/ll_rw_blk.c new file mode 100644 index 0000000..8931a81 --- /dev/null +++ b/src/kernel/blk_drv/ll_rw_blk.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * linux/kernel/blk_dev/ll_rw.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This handles all read/write requests to block devices | ||
9 | */ | ||
10 | #include <errno.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/system.h> | ||
14 | |||
15 | #include "blk.h" | ||
16 | |||
17 | /* | ||
18 | * The request-struct contains all necessary data | ||
19 | * to load a nr of sectors into memory | ||
20 | */ | ||
21 | struct request request[NR_REQUEST]; | ||
22 | |||
23 | /* | ||
24 | * used to wait on when there are no free requests | ||
25 | */ | ||
26 | struct task_struct * wait_for_request = NULL; | ||
27 | |||
28 | /* blk_dev_struct is: | ||
29 | * do_request-address | ||
30 | * next-request | ||
31 | */ | ||
32 | struct blk_dev_struct blk_dev[NR_BLK_DEV] = { | ||
33 | { NULL, NULL }, /* no_dev */ | ||
34 | { NULL, NULL }, /* dev mem */ | ||
35 | { NULL, NULL }, /* dev fd */ | ||
36 | { NULL, NULL }, /* dev hd */ | ||
37 | { NULL, NULL }, /* dev ttyx */ | ||
38 | { NULL, NULL }, /* dev tty */ | ||
39 | { NULL, NULL } /* dev lp */ | ||
40 | }; | ||
41 | |||
42 | static inline void lock_buffer(struct buffer_head * bh) | ||
43 | { | ||
44 | cli(); | ||
45 | while (bh->b_lock) | ||
46 | sleep_on(&bh->b_wait); | ||
47 | bh->b_lock=1; | ||
48 | sti(); | ||
49 | } | ||
50 | |||
51 | static inline void unlock_buffer(struct buffer_head * bh) | ||
52 | { | ||
53 | if (!bh->b_lock) | ||
54 | printk("ll_rw_block.c: buffer not locked\n\r"); | ||
55 | bh->b_lock = 0; | ||
56 | wake_up(&bh->b_wait); | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * add-request adds a request to the linked list. | ||
61 | * It disables interrupts so that it can muck with the | ||
62 | * request-lists in peace. | ||
63 | */ | ||
64 | static void add_request(struct blk_dev_struct * dev, struct request * req) | ||
65 | { | ||
66 | struct request * tmp; | ||
67 | |||
68 | req->next = NULL; | ||
69 | cli(); | ||
70 | if (req->bh) | ||
71 | req->bh->b_dirt = 0; | ||
72 | if (!(tmp = dev->current_request)) { | ||
73 | dev->current_request = req; | ||
74 | sti(); | ||
75 | (dev->request_fn)(); | ||
76 | return; | ||
77 | } | ||
78 | for ( ; tmp->next ; tmp=tmp->next) | ||
79 | if ((IN_ORDER(tmp,req) || | ||
80 | !IN_ORDER(tmp,tmp->next)) && | ||
81 | IN_ORDER(req,tmp->next)) | ||
82 | break; | ||
83 | req->next=tmp->next; | ||
84 | tmp->next=req; | ||
85 | sti(); | ||
86 | } | ||
87 | |||
88 | static void make_request(int major,int rw, struct buffer_head * bh) | ||
89 | { | ||
90 | struct request * req; | ||
91 | int rw_ahead; | ||
92 | |||
93 | /* WRITEA/READA is special case - it is not really needed, so if the */ | ||
94 | /* buffer is locked, we just forget about it, else it's a normal read */ | ||
95 | if ((rw_ahead = (rw == READA || rw == WRITEA))) { | ||
96 | if (bh->b_lock) | ||
97 | return; | ||
98 | if (rw == READA) | ||
99 | rw = READ; | ||
100 | else | ||
101 | rw = WRITE; | ||
102 | } | ||
103 | if (rw!=READ && rw!=WRITE) | ||
104 | panic("Bad block dev command, must be R/W/RA/WA"); | ||
105 | lock_buffer(bh); | ||
106 | if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { | ||
107 | unlock_buffer(bh); | ||
108 | return; | ||
109 | } | ||
110 | repeat: | ||
111 | /* we don't allow the write-requests to fill up the queue completely: | ||
112 | * we want some room for reads: they take precedence. The last third | ||
113 | * of the requests are only for reads. | ||
114 | */ | ||
115 | if (rw == READ) | ||
116 | req = request+NR_REQUEST; | ||
117 | else | ||
118 | req = request+((NR_REQUEST*2)/3); | ||
119 | /* find an empty request */ | ||
120 | while (--req >= request) | ||
121 | if (req->dev<0) | ||
122 | break; | ||
123 | /* if none found, sleep on new requests: check for rw_ahead */ | ||
124 | if (req < request) { | ||
125 | if (rw_ahead) { | ||
126 | unlock_buffer(bh); | ||
127 | return; | ||
128 | } | ||
129 | sleep_on(&wait_for_request); | ||
130 | goto repeat; | ||
131 | } | ||
132 | /* fill up the request-info, and add it to the queue */ | ||
133 | req->dev = bh->b_dev; | ||
134 | req->cmd = rw; | ||
135 | req->errors=0; | ||
136 | req->sector = bh->b_blocknr<<1; | ||
137 | req->nr_sectors = 2; | ||
138 | req->buffer = bh->b_data; | ||
139 | req->waiting = NULL; | ||
140 | req->bh = bh; | ||
141 | req->next = NULL; | ||
142 | add_request(major+blk_dev,req); | ||
143 | } | ||
144 | |||
145 | void ll_rw_block(int rw, struct buffer_head * bh) | ||
146 | { | ||
147 | unsigned int major; | ||
148 | |||
149 | if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || | ||
150 | !(blk_dev[major].request_fn)) { | ||
151 | printk("Trying to read nonexistent block-device\n\r"); | ||
152 | return; | ||
153 | } | ||
154 | make_request(major,rw,bh); | ||
155 | } | ||
156 | |||
157 | void blk_dev_init(void) | ||
158 | { | ||
159 | int i; | ||
160 | |||
161 | for (i=0 ; i<NR_REQUEST ; i++) { | ||
162 | request[i].dev = -1; | ||
163 | request[i].next = NULL; | ||
164 | } | ||
165 | } | ||
diff --git a/src/kernel/blk_drv/ramdisk.c b/src/kernel/blk_drv/ramdisk.c new file mode 100644 index 0000000..dc99f7c --- /dev/null +++ b/src/kernel/blk_drv/ramdisk.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * linux/kernel/blk_drv/ramdisk.c | ||
3 | * | ||
4 | * Written by Theodore Ts'o, 12/2/91 | ||
5 | */ | ||
6 | |||
7 | #include <string.h> | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/system.h> | ||
14 | #include <asm/segment.h> | ||
15 | #include <asm/memory.h> | ||
16 | |||
17 | #define MAJOR_NR 1 | ||
18 | #include "blk.h" | ||
19 | |||
20 | char *rd_start; | ||
21 | int rd_length = 0; | ||
22 | |||
23 | void do_rd_request(void) | ||
24 | { | ||
25 | int len; | ||
26 | char *addr; | ||
27 | |||
28 | INIT_REQUEST; | ||
29 | addr = rd_start + (CURRENT->sector << 9); | ||
30 | len = CURRENT->nr_sectors << 9; | ||
31 | if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) { | ||
32 | end_request(0); | ||
33 | goto repeat; | ||
34 | } | ||
35 | if (CURRENT-> cmd == WRITE) { | ||
36 | (void ) memcpy(addr, | ||
37 | CURRENT->buffer, | ||
38 | len); | ||
39 | } else if (CURRENT->cmd == READ) { | ||
40 | (void) memcpy(CURRENT->buffer, | ||
41 | addr, | ||
42 | len); | ||
43 | } else | ||
44 | panic("unknown ramdisk-command"); | ||
45 | end_request(1); | ||
46 | goto repeat; | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Returns amount of memory which needs to be reserved. | ||
51 | */ | ||
52 | long rd_init(long mem_start, int length) | ||
53 | { | ||
54 | int i; | ||
55 | char *cp; | ||
56 | |||
57 | blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; | ||
58 | rd_start = (char *) mem_start; | ||
59 | rd_length = length; | ||
60 | cp = rd_start; | ||
61 | for (i=0; i < length; i++) | ||
62 | *cp++ = '\0'; | ||
63 | return(length); | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * If the root device is the ram disk, try to load it. | ||
68 | * In order to do this, the root device is originally set to the | ||
69 | * floppy, and we later change it to be ram disk. | ||
70 | */ | ||
71 | void rd_load(void) | ||
72 | { | ||
73 | struct buffer_head *bh; | ||
74 | struct super_block s; | ||
75 | int block = 256; /* Start at block 256 */ | ||
76 | int i = 1; | ||
77 | int nblocks; | ||
78 | char *cp; /* Move pointer */ | ||
79 | |||
80 | if (!rd_length) | ||
81 | return; | ||
82 | printk("Ram disk: %d bytes, starting at 0x%x\n", rd_length, | ||
83 | (int) rd_start); | ||
84 | if (MAJOR(ROOT_DEV) != 2) | ||
85 | return; | ||
86 | bh = breada(ROOT_DEV,block+1,block,block+2,-1); | ||
87 | if (!bh) { | ||
88 | printk("Disk error while looking for ramdisk!\n"); | ||
89 | return; | ||
90 | } | ||
91 | *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data); | ||
92 | brelse(bh); | ||
93 | if (s.s_magic != SUPER_MAGIC) | ||
94 | /* No ram disk image present, assume normal floppy boot */ | ||
95 | return; | ||
96 | nblocks = s.s_nzones << s.s_log_zone_size; | ||
97 | if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { | ||
98 | printk("Ram disk image too big! (%d blocks, %d avail)\n", | ||
99 | nblocks, rd_length >> BLOCK_SIZE_BITS); | ||
100 | return; | ||
101 | } | ||
102 | printk("Loading %d bytes into ram disk... 0000k", | ||
103 | nblocks << BLOCK_SIZE_BITS); | ||
104 | cp = rd_start; | ||
105 | while (nblocks) { | ||
106 | if (nblocks > 2) | ||
107 | bh = breada(ROOT_DEV, block, block+1, block+2, -1); | ||
108 | else | ||
109 | bh = bread(ROOT_DEV, block); | ||
110 | if (!bh) { | ||
111 | printk("I/O error on block %d, aborting load\n", | ||
112 | block); | ||
113 | return; | ||
114 | } | ||
115 | (void) memcpy(cp, bh->b_data, BLOCK_SIZE); | ||
116 | brelse(bh); | ||
117 | printk("\010\010\010\010\010%4dk",i); | ||
118 | cp += BLOCK_SIZE; | ||
119 | block++; | ||
120 | nblocks--; | ||
121 | i++; | ||
122 | } | ||
123 | printk("\010\010\010\010\010done \n"); | ||
124 | ROOT_DEV=0x0101; | ||
125 | } | ||
diff --git a/src/kernel/chr_drv/Makefile b/src/kernel/chr_drv/Makefile new file mode 100644 index 0000000..3dd5449 --- /dev/null +++ b/src/kernel/chr_drv/Makefile | |||
@@ -0,0 +1,67 @@ | |||
1 | # | ||
2 | # Makefile for the FREAX-kernel character device drivers. | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | include ../../Makefile.header | ||
10 | |||
11 | CFLAGS += -I../../include | ||
12 | CPP += -I../../include | ||
13 | |||
14 | .c.s: | ||
15 | @$(CC) $(CFLAGS) \ | ||
16 | -S -o $*.s $< | ||
17 | .s.o: | ||
18 | @$(AS) -o $*.o $< | ||
19 | .c.o: | ||
20 | @$(CC) $(CFLAGS) \ | ||
21 | -c -o $*.o $< | ||
22 | |||
23 | OBJS = tty_io.o console.o keyboard.o serial.o rs_io.o \ | ||
24 | tty_ioctl.o | ||
25 | |||
26 | chr_drv.a: $(OBJS) | ||
27 | @$(AR) rcs chr_drv.a $(OBJS) | ||
28 | sync | ||
29 | |||
30 | keyboard.s: kb.S ../../include/linux/config.h | ||
31 | @$(CPP) kb.S -o keyboard.s | ||
32 | |||
33 | clean: | ||
34 | @rm -f core *.o *.a tmp_make keyboard.s | ||
35 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
36 | |||
37 | dep: | ||
38 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
39 | @(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ | ||
40 | $(CPP) -M $$i;done) >> tmp_make | ||
41 | @cp tmp_make Makefile | ||
42 | |||
43 | ### Dependencies: | ||
44 | console.s console.o: console.c ../../include/linux/sched.h \ | ||
45 | ../../include/linux/head.h ../../include/linux/fs.h \ | ||
46 | ../../include/sys/types.h ../../include/linux/mm.h \ | ||
47 | ../../include/signal.h ../../include/linux/tty.h \ | ||
48 | ../../include/termios.h ../../include/asm/io.h \ | ||
49 | ../../include/asm/system.h | ||
50 | serial.s serial.o: serial.c ../../include/linux/tty.h ../../include/termios.h \ | ||
51 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
52 | ../../include/linux/fs.h ../../include/sys/types.h \ | ||
53 | ../../include/linux/mm.h ../../include/signal.h \ | ||
54 | ../../include/asm/system.h ../../include/asm/io.h | ||
55 | tty_io.s tty_io.o: tty_io.c ../../include/ctype.h ../../include/errno.h \ | ||
56 | ../../include/signal.h ../../include/sys/types.h \ | ||
57 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
58 | ../../include/linux/fs.h ../../include/linux/mm.h \ | ||
59 | ../../include/linux/tty.h ../../include/termios.h \ | ||
60 | ../../include/asm/segment.h ../../include/asm/system.h | ||
61 | tty_ioctl.s tty_ioctl.o: tty_ioctl.c ../../include/errno.h ../../include/termios.h \ | ||
62 | ../../include/linux/sched.h ../../include/linux/head.h \ | ||
63 | ../../include/linux/fs.h ../../include/sys/types.h \ | ||
64 | ../../include/linux/mm.h ../../include/signal.h \ | ||
65 | ../../include/linux/kernel.h ../../include/linux/tty.h \ | ||
66 | ../../include/asm/io.h ../../include/asm/segment.h \ | ||
67 | ../../include/asm/system.h | ||
diff --git a/src/kernel/chr_drv/console.c b/src/kernel/chr_drv/console.c new file mode 100644 index 0000000..2529569 --- /dev/null +++ b/src/kernel/chr_drv/console.c | |||
@@ -0,0 +1,710 @@ | |||
1 | /* | ||
2 | * linux/kernel/console.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * console.c | ||
9 | * | ||
10 | * This module implements the console io functions | ||
11 | * 'void con_init(void)' | ||
12 | * 'void con_write(struct tty_queue * queue)' | ||
13 | * Hopefully this will be a rather complete VT102 implementation. | ||
14 | * | ||
15 | * Beeping thanks to John T Kohl. | ||
16 | */ | ||
17 | |||
18 | /* | ||
19 | * NOTE!!! We sometimes disable and enable interrupts for a short while | ||
20 | * (to put a word in video IO), but this will work even for keyboard | ||
21 | * interrupts. We know interrupts aren't enabled when getting a keyboard | ||
22 | * interrupt, as we use trap-gates. Hopefully all is well. | ||
23 | */ | ||
24 | |||
25 | /* | ||
26 | * Code to check for different video-cards mostly by Galen Hunt, | ||
27 | * <g-hunt@ee.utah.edu> | ||
28 | */ | ||
29 | |||
30 | #include <linux/sched.h> | ||
31 | #include <linux/tty.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <asm/system.h> | ||
34 | |||
35 | /* | ||
36 | * These are set up by the setup-routine at boot-time: | ||
37 | */ | ||
38 | |||
39 | #define ORIG_X (*(unsigned char *)0x90000) | ||
40 | #define ORIG_Y (*(unsigned char *)0x90001) | ||
41 | #define ORIG_VIDEO_PAGE (*(unsigned short *)0x90004) | ||
42 | #define ORIG_VIDEO_MODE ((*(unsigned short *)0x90006) & 0xff) | ||
43 | #define ORIG_VIDEO_COLS (((*(unsigned short *)0x90006) & 0xff00) >> 8) | ||
44 | #define ORIG_VIDEO_LINES (25) | ||
45 | #define ORIG_VIDEO_EGA_AX (*(unsigned short *)0x90008) | ||
46 | #define ORIG_VIDEO_EGA_BX (*(unsigned short *)0x9000a) | ||
47 | #define ORIG_VIDEO_EGA_CX (*(unsigned short *)0x9000c) | ||
48 | |||
49 | #define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ | ||
50 | #define VIDEO_TYPE_CGA 0x11 /* CGA Display */ | ||
51 | #define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ | ||
52 | #define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ | ||
53 | |||
54 | #define NPAR 16 | ||
55 | |||
56 | extern void keyboard_interrupt(void); | ||
57 | |||
58 | static unsigned char video_type; /* Type of display being used */ | ||
59 | static unsigned long video_num_columns; /* Number of text columns */ | ||
60 | static unsigned long video_size_row; /* Bytes per row */ | ||
61 | static unsigned long video_num_lines; /* Number of test lines */ | ||
62 | static unsigned char video_page; /* Initial video page */ | ||
63 | static unsigned long video_mem_start; /* Start of video RAM */ | ||
64 | static unsigned long video_mem_end; /* End of video RAM (sort of) */ | ||
65 | static unsigned short video_port_reg; /* Video register select port */ | ||
66 | static unsigned short video_port_val; /* Video register value port */ | ||
67 | static unsigned short video_erase_char; /* Char+Attrib to erase with */ | ||
68 | |||
69 | static unsigned long origin; /* Used for EGA/VGA fast scroll */ | ||
70 | static unsigned long scr_end; /* Used for EGA/VGA fast scroll */ | ||
71 | static unsigned long pos; | ||
72 | static unsigned long x,y; | ||
73 | static unsigned long top,bottom; | ||
74 | static unsigned long state=0; | ||
75 | static unsigned long npar,par[NPAR]; | ||
76 | static unsigned long ques=0; | ||
77 | static unsigned char attr=0x07; | ||
78 | |||
79 | static void sysbeep(void); | ||
80 | |||
81 | /* | ||
82 | * this is what the terminal answers to a ESC-Z or csi0c | ||
83 | * query (= vt100 response). | ||
84 | */ | ||
85 | #define RESPONSE "\033[?1;2c" | ||
86 | |||
87 | /* NOTE! gotoxy thinks x==video_num_columns is ok */ | ||
88 | static inline void gotoxy(unsigned int new_x,unsigned int new_y) | ||
89 | { | ||
90 | if (new_x > video_num_columns || new_y >= video_num_lines) | ||
91 | return; | ||
92 | x=new_x; | ||
93 | y=new_y; | ||
94 | pos=origin + y*video_size_row + (x<<1); | ||
95 | } | ||
96 | |||
97 | static inline void set_origin(void) | ||
98 | { | ||
99 | cli(); | ||
100 | outb_p(12, video_port_reg); | ||
101 | outb_p(0xff&((origin-video_mem_start)>>9), video_port_val); | ||
102 | outb_p(13, video_port_reg); | ||
103 | outb_p(0xff&((origin-video_mem_start)>>1), video_port_val); | ||
104 | sti(); | ||
105 | } | ||
106 | |||
107 | static void scrup(void) | ||
108 | { | ||
109 | if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) | ||
110 | { | ||
111 | if (!top && bottom == video_num_lines) { | ||
112 | origin += video_size_row; | ||
113 | pos += video_size_row; | ||
114 | scr_end += video_size_row; | ||
115 | if (scr_end > video_mem_end) { | ||
116 | __asm__("cld\n\t" | ||
117 | "rep\n\t" | ||
118 | "movsl\n\t" | ||
119 | "movl video_num_columns,%1\n\t" | ||
120 | "rep\n\t" | ||
121 | "stosw" | ||
122 | ::"a" (video_erase_char), | ||
123 | "c" ((video_num_lines-1)*video_num_columns>>1), | ||
124 | "D" (video_mem_start), | ||
125 | "S" (origin) | ||
126 | ); | ||
127 | scr_end -= origin-video_mem_start; | ||
128 | pos -= origin-video_mem_start; | ||
129 | origin = video_mem_start; | ||
130 | } else { | ||
131 | __asm__("cld\n\t" | ||
132 | "rep\n\t" | ||
133 | "stosw" | ||
134 | ::"a" (video_erase_char), | ||
135 | "c" (video_num_columns), | ||
136 | "D" (scr_end-video_size_row) | ||
137 | ); | ||
138 | } | ||
139 | set_origin(); | ||
140 | } else { | ||
141 | __asm__("cld\n\t" | ||
142 | "rep\n\t" | ||
143 | "movsl\n\t" | ||
144 | "movl video_num_columns,%%ecx\n\t" | ||
145 | "rep\n\t" | ||
146 | "stosw" | ||
147 | ::"a" (video_erase_char), | ||
148 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
149 | "D" (origin+video_size_row*top), | ||
150 | "S" (origin+video_size_row*(top+1)) | ||
151 | ); | ||
152 | } | ||
153 | } | ||
154 | else /* Not EGA/VGA */ | ||
155 | { | ||
156 | __asm__("cld\n\t" | ||
157 | "rep\n\t" | ||
158 | "movsl\n\t" | ||
159 | "movl video_num_columns,%%ecx\n\t" | ||
160 | "rep\n\t" | ||
161 | "stosw" | ||
162 | ::"a" (video_erase_char), | ||
163 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
164 | "D" (origin+video_size_row*top), | ||
165 | "S" (origin+video_size_row*(top+1)) | ||
166 | ); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static void scrdown(void) | ||
171 | { | ||
172 | if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM) | ||
173 | { | ||
174 | __asm__("std\n\t" | ||
175 | "rep\n\t" | ||
176 | "movsl\n\t" | ||
177 | "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ | ||
178 | "movl video_num_columns,%%ecx\n\t" | ||
179 | "rep\n\t" | ||
180 | "stosw" | ||
181 | ::"a" (video_erase_char), | ||
182 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
183 | "D" (origin+video_size_row*bottom-4), | ||
184 | "S" (origin+video_size_row*(bottom-1)-4) | ||
185 | ); | ||
186 | } | ||
187 | else /* Not EGA/VGA */ | ||
188 | { | ||
189 | __asm__("std\n\t" | ||
190 | "rep\n\t" | ||
191 | "movsl\n\t" | ||
192 | "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ | ||
193 | "movl video_num_columns,%%ecx\n\t" | ||
194 | "rep\n\t" | ||
195 | "stosw" | ||
196 | ::"a" (video_erase_char), | ||
197 | "c" ((bottom-top-1)*video_num_columns>>1), | ||
198 | "D" (origin+video_size_row*bottom-4), | ||
199 | "S" (origin+video_size_row*(bottom-1)-4) | ||
200 | ); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | static void lf(void) | ||
205 | { | ||
206 | if (y+1<bottom) { | ||
207 | y++; | ||
208 | pos += video_size_row; | ||
209 | return; | ||
210 | } | ||
211 | scrup(); | ||
212 | } | ||
213 | |||
214 | static void ri(void) | ||
215 | { | ||
216 | if (y>top) { | ||
217 | y--; | ||
218 | pos -= video_size_row; | ||
219 | return; | ||
220 | } | ||
221 | scrdown(); | ||
222 | } | ||
223 | |||
224 | static void cr(void) | ||
225 | { | ||
226 | pos -= x<<1; | ||
227 | x=0; | ||
228 | } | ||
229 | |||
230 | static void del(void) | ||
231 | { | ||
232 | if (x) { | ||
233 | pos -= 2; | ||
234 | x--; | ||
235 | *(unsigned short *)pos = video_erase_char; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | static void csi_J(int par) | ||
240 | { | ||
241 | long count; | ||
242 | long start; | ||
243 | |||
244 | switch (par) { | ||
245 | case 0: /* erase from cursor to end of display */ | ||
246 | count = (scr_end-pos)>>1; | ||
247 | start = pos; | ||
248 | break; | ||
249 | case 1: /* erase from start to cursor */ | ||
250 | count = (pos-origin)>>1; | ||
251 | start = origin; | ||
252 | break; | ||
253 | case 2: /* erase whole display */ | ||
254 | count = video_num_columns * video_num_lines; | ||
255 | start = origin; | ||
256 | break; | ||
257 | default: | ||
258 | return; | ||
259 | } | ||
260 | __asm__("cld\n\t" | ||
261 | "rep\n\t" | ||
262 | "stosw\n\t" | ||
263 | ::"c" (count), | ||
264 | "D" (start),"a" (video_erase_char) | ||
265 | ); | ||
266 | } | ||
267 | |||
268 | static void csi_K(int par) | ||
269 | { | ||
270 | long count; | ||
271 | long start; | ||
272 | |||
273 | switch (par) { | ||
274 | case 0: /* erase from cursor to end of line */ | ||
275 | if (x>=video_num_columns) | ||
276 | return; | ||
277 | count = video_num_columns-x; | ||
278 | start = pos; | ||
279 | break; | ||
280 | case 1: /* erase from start of line to cursor */ | ||
281 | start = pos - (x<<1); | ||
282 | count = (x<video_num_columns)?x:video_num_columns; | ||
283 | break; | ||
284 | case 2: /* erase whole line */ | ||
285 | start = pos - (x<<1); | ||
286 | count = video_num_columns; | ||
287 | break; | ||
288 | default: | ||
289 | return; | ||
290 | } | ||
291 | __asm__("cld\n\t" | ||
292 | "rep\n\t" | ||
293 | "stosw\n\t" | ||
294 | ::"c" (count), | ||
295 | "D" (start),"a" (video_erase_char) | ||
296 | ); | ||
297 | } | ||
298 | |||
299 | void csi_m(void) | ||
300 | { | ||
301 | int i; | ||
302 | |||
303 | for (i=0;i<=npar;i++) | ||
304 | switch (par[i]) { | ||
305 | case 0:attr=0x07;break; | ||
306 | case 1:attr=0x0f;break; | ||
307 | case 4:attr=0x0f;break; | ||
308 | case 7:attr=0x70;break; | ||
309 | case 27:attr=0x07;break; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | static inline void set_cursor(void) | ||
314 | { | ||
315 | cli(); | ||
316 | outb_p(14, video_port_reg); | ||
317 | outb_p(0xff&((pos-video_mem_start)>>9), video_port_val); | ||
318 | outb_p(15, video_port_reg); | ||
319 | outb_p(0xff&((pos-video_mem_start)>>1), video_port_val); | ||
320 | sti(); | ||
321 | } | ||
322 | |||
323 | static void respond(struct tty_struct * tty) | ||
324 | { | ||
325 | char * p = RESPONSE; | ||
326 | |||
327 | cli(); | ||
328 | while (*p) { | ||
329 | PUTCH(*p,tty->read_q); | ||
330 | p++; | ||
331 | } | ||
332 | sti(); | ||
333 | copy_to_cooked(tty); | ||
334 | } | ||
335 | |||
336 | static void insert_char(void) | ||
337 | { | ||
338 | int i=x; | ||
339 | unsigned short tmp, old = video_erase_char; | ||
340 | unsigned short * p = (unsigned short *) pos; | ||
341 | |||
342 | while (i++<video_num_columns) { | ||
343 | tmp=*p; | ||
344 | *p=old; | ||
345 | old=tmp; | ||
346 | p++; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static void insert_line(void) | ||
351 | { | ||
352 | int oldtop,oldbottom; | ||
353 | |||
354 | oldtop=top; | ||
355 | oldbottom=bottom; | ||
356 | top=y; | ||
357 | bottom = video_num_lines; | ||
358 | scrdown(); | ||
359 | top=oldtop; | ||
360 | bottom=oldbottom; | ||
361 | } | ||
362 | |||
363 | static void delete_char(void) | ||
364 | { | ||
365 | int i; | ||
366 | unsigned short * p = (unsigned short *) pos; | ||
367 | |||
368 | if (x>=video_num_columns) | ||
369 | return; | ||
370 | i = x; | ||
371 | while (++i < video_num_columns) { | ||
372 | *p = *(p+1); | ||
373 | p++; | ||
374 | } | ||
375 | *p = video_erase_char; | ||
376 | } | ||
377 | |||
378 | static void delete_line(void) | ||
379 | { | ||
380 | int oldtop,oldbottom; | ||
381 | |||
382 | oldtop=top; | ||
383 | oldbottom=bottom; | ||
384 | top=y; | ||
385 | bottom = video_num_lines; | ||
386 | scrup(); | ||
387 | top=oldtop; | ||
388 | bottom=oldbottom; | ||
389 | } | ||
390 | |||
391 | static void csi_at(unsigned int nr) | ||
392 | { | ||
393 | if (nr > video_num_columns) | ||
394 | nr = video_num_columns; | ||
395 | else if (!nr) | ||
396 | nr = 1; | ||
397 | while (nr--) | ||
398 | insert_char(); | ||
399 | } | ||
400 | |||
401 | static void csi_L(unsigned int nr) | ||
402 | { | ||
403 | if (nr > video_num_lines) | ||
404 | nr = video_num_lines; | ||
405 | else if (!nr) | ||
406 | nr = 1; | ||
407 | while (nr--) | ||
408 | insert_line(); | ||
409 | } | ||
410 | |||
411 | static void csi_P(unsigned int nr) | ||
412 | { | ||
413 | if (nr > video_num_columns) | ||
414 | nr = video_num_columns; | ||
415 | else if (!nr) | ||
416 | nr = 1; | ||
417 | while (nr--) | ||
418 | delete_char(); | ||
419 | } | ||
420 | |||
421 | static void csi_M(unsigned int nr) | ||
422 | { | ||
423 | if (nr > video_num_lines) | ||
424 | nr = video_num_lines; | ||
425 | else if (!nr) | ||
426 | nr=1; | ||
427 | while (nr--) | ||
428 | delete_line(); | ||
429 | } | ||
430 | |||
431 | static int saved_x=0; | ||
432 | static int saved_y=0; | ||
433 | |||
434 | static void save_cur(void) | ||
435 | { | ||
436 | saved_x=x; | ||
437 | saved_y=y; | ||
438 | } | ||
439 | |||
440 | static void restore_cur(void) | ||
441 | { | ||
442 | gotoxy(saved_x, saved_y); | ||
443 | } | ||
444 | |||
445 | void con_write(struct tty_struct * tty) | ||
446 | { | ||
447 | int nr; | ||
448 | char c; | ||
449 | |||
450 | nr = CHARS(tty->write_q); | ||
451 | while (nr--) { | ||
452 | GETCH(tty->write_q,c); | ||
453 | switch(state) { | ||
454 | case 0: | ||
455 | if (c>31 && c<127) { | ||
456 | if (x>=video_num_columns) { | ||
457 | x -= video_num_columns; | ||
458 | pos -= video_size_row; | ||
459 | lf(); | ||
460 | } | ||
461 | __asm__("movb attr,%%ah\n\t" | ||
462 | "movw %%ax,%1\n\t" | ||
463 | ::"a" (c),"m" (*(short *)pos) | ||
464 | ); | ||
465 | pos += 2; | ||
466 | x++; | ||
467 | } else if (c==27) | ||
468 | state=1; | ||
469 | else if (c==10 || c==11 || c==12) | ||
470 | lf(); | ||
471 | else if (c==13) | ||
472 | cr(); | ||
473 | else if (c==ERASE_CHAR(tty)) | ||
474 | del(); | ||
475 | else if (c==8) { | ||
476 | if (x) { | ||
477 | x--; | ||
478 | pos -= 2; | ||
479 | } | ||
480 | } else if (c==9) { | ||
481 | c=8-(x&7); | ||
482 | x += c; | ||
483 | pos += c<<1; | ||
484 | if (x>video_num_columns) { | ||
485 | x -= video_num_columns; | ||
486 | pos -= video_size_row; | ||
487 | lf(); | ||
488 | } | ||
489 | c=9; | ||
490 | } else if (c==7) | ||
491 | sysbeep(); | ||
492 | break; | ||
493 | case 1: | ||
494 | state=0; | ||
495 | if (c=='[') | ||
496 | state=2; | ||
497 | else if (c=='E') | ||
498 | gotoxy(0,y+1); | ||
499 | else if (c=='M') | ||
500 | ri(); | ||
501 | else if (c=='D') | ||
502 | lf(); | ||
503 | else if (c=='Z') | ||
504 | respond(tty); | ||
505 | else if (x=='7') | ||
506 | save_cur(); | ||
507 | else if (x=='8') | ||
508 | restore_cur(); | ||
509 | break; | ||
510 | case 2: | ||
511 | for(npar=0;npar<NPAR;npar++) | ||
512 | par[npar]=0; | ||
513 | npar=0; | ||
514 | state=3; | ||
515 | if ((ques=(c=='?'))) | ||
516 | break; | ||
517 | case 3: | ||
518 | if (c==';' && npar<NPAR-1) { | ||
519 | npar++; | ||
520 | break; | ||
521 | } else if (c>='0' && c<='9') { | ||
522 | par[npar]=10*par[npar]+c-'0'; | ||
523 | break; | ||
524 | } else state=4; | ||
525 | case 4: | ||
526 | state=0; | ||
527 | switch(c) { | ||
528 | case 'G': case '`': | ||
529 | if (par[0]) par[0]--; | ||
530 | gotoxy(par[0],y); | ||
531 | break; | ||
532 | case 'A': | ||
533 | if (!par[0]) par[0]++; | ||
534 | gotoxy(x,y-par[0]); | ||
535 | break; | ||
536 | case 'B': case 'e': | ||
537 | if (!par[0]) par[0]++; | ||
538 | gotoxy(x,y+par[0]); | ||
539 | break; | ||
540 | case 'C': case 'a': | ||
541 | if (!par[0]) par[0]++; | ||
542 | gotoxy(x+par[0],y); | ||
543 | break; | ||
544 | case 'D': | ||
545 | if (!par[0]) par[0]++; | ||
546 | gotoxy(x-par[0],y); | ||
547 | break; | ||
548 | case 'E': | ||
549 | if (!par[0]) par[0]++; | ||
550 | gotoxy(0,y+par[0]); | ||
551 | break; | ||
552 | case 'F': | ||
553 | if (!par[0]) par[0]++; | ||
554 | gotoxy(0,y-par[0]); | ||
555 | break; | ||
556 | case 'd': | ||
557 | if (par[0]) par[0]--; | ||
558 | gotoxy(x,par[0]); | ||
559 | break; | ||
560 | case 'H': case 'f': | ||
561 | if (par[0]) par[0]--; | ||
562 | if (par[1]) par[1]--; | ||
563 | gotoxy(par[1],par[0]); | ||
564 | break; | ||
565 | case 'J': | ||
566 | csi_J(par[0]); | ||
567 | break; | ||
568 | case 'K': | ||
569 | csi_K(par[0]); | ||
570 | break; | ||
571 | case 'L': | ||
572 | csi_L(par[0]); | ||
573 | break; | ||
574 | case 'M': | ||
575 | csi_M(par[0]); | ||
576 | break; | ||
577 | case 'P': | ||
578 | csi_P(par[0]); | ||
579 | break; | ||
580 | case '@': | ||
581 | csi_at(par[0]); | ||
582 | break; | ||
583 | case 'm': | ||
584 | csi_m(); | ||
585 | break; | ||
586 | case 'r': | ||
587 | if (par[0]) par[0]--; | ||
588 | if (!par[1]) par[1] = video_num_lines; | ||
589 | if (par[0] < par[1] && | ||
590 | par[1] <= video_num_lines) { | ||
591 | top=par[0]; | ||
592 | bottom=par[1]; | ||
593 | } | ||
594 | break; | ||
595 | case 's': | ||
596 | save_cur(); | ||
597 | break; | ||
598 | case 'u': | ||
599 | restore_cur(); | ||
600 | break; | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | set_cursor(); | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * void con_init(void); | ||
609 | * | ||
610 | * This routine initalizes console interrupts, and does nothing | ||
611 | * else. If you want the screen to clear, call tty_write with | ||
612 | * the appropriate escape-sequece. | ||
613 | * | ||
614 | * Reads the information preserved by setup.s to determine the current display | ||
615 | * type and sets everything accordingly. | ||
616 | */ | ||
617 | void con_init(void) | ||
618 | { | ||
619 | register unsigned char a; | ||
620 | char *display_desc = "????"; | ||
621 | char *display_ptr; | ||
622 | |||
623 | video_num_columns = ORIG_VIDEO_COLS; | ||
624 | video_size_row = video_num_columns * 2; | ||
625 | video_num_lines = ORIG_VIDEO_LINES; | ||
626 | video_page = ORIG_VIDEO_PAGE; | ||
627 | video_erase_char = 0x0720; | ||
628 | |||
629 | if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */ | ||
630 | { | ||
631 | video_mem_start = 0xb0000; | ||
632 | video_port_reg = 0x3b4; | ||
633 | video_port_val = 0x3b5; | ||
634 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) | ||
635 | { | ||
636 | video_type = VIDEO_TYPE_EGAM; | ||
637 | video_mem_end = 0xb8000; | ||
638 | display_desc = "EGAm"; | ||
639 | } | ||
640 | else | ||
641 | { | ||
642 | video_type = VIDEO_TYPE_MDA; | ||
643 | video_mem_end = 0xb2000; | ||
644 | display_desc = "*MDA"; | ||
645 | } | ||
646 | } | ||
647 | else /* If not, it is color. */ | ||
648 | { | ||
649 | video_mem_start = 0xb8000; | ||
650 | video_port_reg = 0x3d4; | ||
651 | video_port_val = 0x3d5; | ||
652 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) | ||
653 | { | ||
654 | video_type = VIDEO_TYPE_EGAC; | ||
655 | video_mem_end = 0xbc000; | ||
656 | display_desc = "EGAc"; | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | video_type = VIDEO_TYPE_CGA; | ||
661 | video_mem_end = 0xba000; | ||
662 | display_desc = "*CGA"; | ||
663 | } | ||
664 | } | ||
665 | |||
666 | /* Let the user known what kind of display driver we are using */ | ||
667 | |||
668 | display_ptr = ((char *)video_mem_start) + video_size_row - 8; | ||
669 | while (*display_desc) | ||
670 | { | ||
671 | *display_ptr++ = *display_desc++; | ||
672 | display_ptr++; | ||
673 | } | ||
674 | |||
675 | /* Initialize the variables used for scrolling (mostly EGA/VGA) */ | ||
676 | |||
677 | origin = video_mem_start; | ||
678 | scr_end = video_mem_start + video_num_lines * video_size_row; | ||
679 | top = 0; | ||
680 | bottom = video_num_lines; | ||
681 | |||
682 | gotoxy(ORIG_X,ORIG_Y); | ||
683 | set_trap_gate(0x21,&keyboard_interrupt); | ||
684 | outb_p(inb_p(0x21)&0xfd,0x21); | ||
685 | a=inb_p(0x61); | ||
686 | outb_p(a|0x80,0x61); | ||
687 | outb(a,0x61); | ||
688 | } | ||
689 | /* from bsd-net-2: */ | ||
690 | |||
691 | void sysbeepstop(void) | ||
692 | { | ||
693 | /* disable counter 2 */ | ||
694 | outb(inb_p(0x61)&0xFC, 0x61); | ||
695 | } | ||
696 | |||
697 | int beepcount = 0; | ||
698 | |||
699 | static void sysbeep(void) | ||
700 | { | ||
701 | /* enable counter 2 */ | ||
702 | outb_p(inb_p(0x61)|3, 0x61); | ||
703 | /* set command for counter 2, 2 byte write */ | ||
704 | outb_p(0xB6, 0x43); | ||
705 | /* send 0x637 for 750 HZ */ | ||
706 | outb_p(0x37, 0x42); | ||
707 | outb(0x06, 0x42); | ||
708 | /* 1/8 second */ | ||
709 | beepcount = HZ/8; | ||
710 | } | ||
diff --git a/src/kernel/chr_drv/kb.S b/src/kernel/chr_drv/kb.S new file mode 100644 index 0000000..ffd28cf --- /dev/null +++ b/src/kernel/chr_drv/kb.S | |||
@@ -0,0 +1,588 @@ | |||
1 | /* | ||
2 | * linux/kernel/keyboard.S | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Thanks to Alfred Leung for US keyboard patches | ||
9 | * Wolfgang Thiel for German keyboard patches | ||
10 | * Marc Corsini for the French keyboard | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | |||
15 | .text | ||
16 | .globl keyboard_interrupt | ||
17 | |||
18 | /* | ||
19 | * these are for the keyboard read functions | ||
20 | */ | ||
21 | size = 1024 /* must be a power of two ! And MUST be the same | ||
22 | as in tty_io.c !!!! */ | ||
23 | head = 4 | ||
24 | tail = 8 | ||
25 | proc_list = 12 | ||
26 | buf = 16 | ||
27 | |||
28 | mode: .byte 0 /* caps, alt, ctrl and shift mode */ | ||
29 | leds: .byte 2 /* num-lock, caps, scroll-lock mode (nom-lock on) */ | ||
30 | e0: .byte 0 | ||
31 | |||
32 | /* | ||
33 | * con_int is the real interrupt routine that reads the | ||
34 | * keyboard scan-code and converts it into the appropriate | ||
35 | * ascii character(s). | ||
36 | */ | ||
37 | keyboard_interrupt: | ||
38 | pushl %eax | ||
39 | pushl %ebx | ||
40 | pushl %ecx | ||
41 | pushl %edx | ||
42 | push %ds | ||
43 | push %es | ||
44 | movl $0x10,%eax | ||
45 | mov %ax,%ds | ||
46 | mov %ax,%es | ||
47 | xor %al,%al /* %eax is scan code */ | ||
48 | inb $0x60,%al | ||
49 | cmpb $0xe0,%al | ||
50 | je set_e0 | ||
51 | cmpb $0xe1,%al | ||
52 | je set_e1 | ||
53 | call *key_table(,%eax,4) | ||
54 | movb $0,e0 | ||
55 | e0_e1: inb $0x61,%al | ||
56 | jmp 1f | ||
57 | 1: jmp 1f | ||
58 | 1: orb $0x80,%al | ||
59 | jmp 1f | ||
60 | 1: jmp 1f | ||
61 | 1: outb %al,$0x61 | ||
62 | jmp 1f | ||
63 | 1: jmp 1f | ||
64 | 1: andb $0x7F,%al | ||
65 | outb %al,$0x61 | ||
66 | movb $0x20,%al | ||
67 | outb %al,$0x20 | ||
68 | pushl $0 | ||
69 | call do_tty_interrupt | ||
70 | addl $4,%esp | ||
71 | pop %es | ||
72 | pop %ds | ||
73 | popl %edx | ||
74 | popl %ecx | ||
75 | popl %ebx | ||
76 | popl %eax | ||
77 | iret | ||
78 | set_e0: movb $1,e0 | ||
79 | jmp e0_e1 | ||
80 | set_e1: movb $2,e0 | ||
81 | jmp e0_e1 | ||
82 | |||
83 | /* | ||
84 | * This routine fills the buffer with max 8 bytes, taken from | ||
85 | * %ebx:%eax. (%edx is high). The bytes are written in the | ||
86 | * order %al,%ah,%eal,%eah,%bl,%bh ... until %eax is zero. | ||
87 | */ | ||
88 | put_queue: | ||
89 | pushl %ecx | ||
90 | pushl %edx | ||
91 | movl table_list,%edx # read-queue for console | ||
92 | movl head(%edx),%ecx | ||
93 | 1: movb %al,buf(%edx,%ecx) | ||
94 | incl %ecx | ||
95 | andl $size-1,%ecx | ||
96 | cmpl tail(%edx),%ecx # buffer full - discard everything | ||
97 | je 3f | ||
98 | shrdl $8,%ebx,%eax | ||
99 | je 2f | ||
100 | shrl $8,%ebx | ||
101 | jmp 1b | ||
102 | 2: movl %ecx,head(%edx) | ||
103 | movl proc_list(%edx),%ecx | ||
104 | testl %ecx,%ecx | ||
105 | je 3f | ||
106 | movl $0,(%ecx) | ||
107 | 3: popl %edx | ||
108 | popl %ecx | ||
109 | ret | ||
110 | |||
111 | ctrl: movb $0x04,%al | ||
112 | jmp 1f | ||
113 | alt: movb $0x10,%al | ||
114 | 1: cmpb $0,e0 | ||
115 | je 2f | ||
116 | addb %al,%al | ||
117 | 2: orb %al,mode | ||
118 | ret | ||
119 | unctrl: movb $0x04,%al | ||
120 | jmp 1f | ||
121 | unalt: movb $0x10,%al | ||
122 | 1: cmpb $0,e0 | ||
123 | je 2f | ||
124 | addb %al,%al | ||
125 | 2: notb %al | ||
126 | andb %al,mode | ||
127 | ret | ||
128 | |||
129 | lshift: | ||
130 | orb $0x01,mode | ||
131 | ret | ||
132 | unlshift: | ||
133 | andb $0xfe,mode | ||
134 | ret | ||
135 | rshift: | ||
136 | orb $0x02,mode | ||
137 | ret | ||
138 | unrshift: | ||
139 | andb $0xfd,mode | ||
140 | ret | ||
141 | |||
142 | caps: testb $0x80,mode | ||
143 | jne 1f | ||
144 | xorb $4,leds | ||
145 | xorb $0x40,mode | ||
146 | orb $0x80,mode | ||
147 | set_leds: | ||
148 | call kb_wait | ||
149 | movb $0xed,%al /* set leds command */ | ||
150 | outb %al,$0x60 | ||
151 | call kb_wait | ||
152 | movb leds,%al | ||
153 | outb %al,$0x60 | ||
154 | ret | ||
155 | uncaps: andb $0x7f,mode | ||
156 | ret | ||
157 | scroll: | ||
158 | xorb $1,leds | ||
159 | jmp set_leds | ||
160 | num: xorb $2,leds | ||
161 | jmp set_leds | ||
162 | |||
163 | /* | ||
164 | * curosr-key/numeric keypad cursor keys are handled here. | ||
165 | * checking for numeric keypad etc. | ||
166 | */ | ||
167 | cursor: | ||
168 | subb $0x47,%al | ||
169 | jb 1f | ||
170 | cmpb $12,%al | ||
171 | ja 1f | ||
172 | jne cur2 /* check for ctrl-alt-del */ | ||
173 | testb $0x0c,mode | ||
174 | je cur2 | ||
175 | testb $0x30,mode | ||
176 | jne reboot | ||
177 | cur2: cmpb $0x01,e0 /* e0 forces cursor movement */ | ||
178 | je cur | ||
179 | testb $0x02,leds /* not num-lock forces cursor */ | ||
180 | je cur | ||
181 | testb $0x03,mode /* shift forces cursor */ | ||
182 | jne cur | ||
183 | xorl %ebx,%ebx | ||
184 | movb num_table(%eax),%al | ||
185 | jmp put_queue | ||
186 | 1: ret | ||
187 | |||
188 | cur: movb cur_table(%eax),%al | ||
189 | cmpb $'9,%al | ||
190 | ja ok_cur | ||
191 | movb $'~,%ah | ||
192 | ok_cur: shll $16,%eax | ||
193 | movw $0x5b1b,%ax | ||
194 | xorl %ebx,%ebx | ||
195 | jmp put_queue | ||
196 | |||
197 | #if defined(KBD_FR) | ||
198 | num_table: | ||
199 | .ascii "789 456 1230." | ||
200 | #else | ||
201 | num_table: | ||
202 | .ascii "789 456 1230," | ||
203 | #endif | ||
204 | cur_table: | ||
205 | .ascii "HA5 DGC YB623" | ||
206 | |||
207 | /* | ||
208 | * this routine handles function keys | ||
209 | */ | ||
210 | func: | ||
211 | pushl %eax | ||
212 | pushl %ecx | ||
213 | pushl %edx | ||
214 | call show_stat | ||
215 | popl %edx | ||
216 | popl %ecx | ||
217 | popl %eax | ||
218 | subb $0x3B,%al | ||
219 | jb end_func | ||
220 | cmpb $9,%al | ||
221 | jbe ok_func | ||
222 | subb $18,%al | ||
223 | cmpb $10,%al | ||
224 | jb end_func | ||
225 | cmpb $11,%al | ||
226 | ja end_func | ||
227 | ok_func: | ||
228 | cmpl $4,%ecx /* check that there is enough room */ | ||
229 | jl end_func | ||
230 | movl func_table(,%eax,4),%eax | ||
231 | xorl %ebx,%ebx | ||
232 | jmp put_queue | ||
233 | end_func: | ||
234 | ret | ||
235 | |||
236 | /* | ||
237 | * function keys send F1:'esc [ [ A' F2:'esc [ [ B' etc. | ||
238 | */ | ||
239 | func_table: | ||
240 | .long 0x415b5b1b,0x425b5b1b,0x435b5b1b,0x445b5b1b | ||
241 | .long 0x455b5b1b,0x465b5b1b,0x475b5b1b,0x485b5b1b | ||
242 | .long 0x495b5b1b,0x4a5b5b1b,0x4b5b5b1b,0x4c5b5b1b | ||
243 | |||
244 | #if defined(KBD_FINNISH) | ||
245 | key_map: | ||
246 | .byte 0,27 | ||
247 | .ascii "1234567890+'" | ||
248 | .byte 127,9 | ||
249 | .ascii "qwertyuiop}" | ||
250 | .byte 0,13,0 | ||
251 | .ascii "asdfghjkl|{" | ||
252 | .byte 0,0 | ||
253 | .ascii "'zxcvbnm,.-" | ||
254 | .byte 0,'*,0,32 /* 36-39 */ | ||
255 | .fill 16,1,0 /* 3A-49 */ | ||
256 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
257 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
258 | .byte '< | ||
259 | .fill 10,1,0 | ||
260 | |||
261 | shift_map: | ||
262 | .byte 0,27 | ||
263 | .ascii "!\"#$%&/()=?`" | ||
264 | .byte 127,9 | ||
265 | .ascii "QWERTYUIOP]^" | ||
266 | .byte 13,0 | ||
267 | .ascii "ASDFGHJKL\\[" | ||
268 | .byte 0,0 | ||
269 | .ascii "*ZXCVBNM;:_" | ||
270 | .byte 0,'*,0,32 /* 36-39 */ | ||
271 | .fill 16,1,0 /* 3A-49 */ | ||
272 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
273 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
274 | .byte '> | ||
275 | .fill 10,1,0 | ||
276 | |||
277 | alt_map: | ||
278 | .byte 0,0 | ||
279 | .ascii "\0@\0$\0\0{[]}\\\0" | ||
280 | .byte 0,0 | ||
281 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
282 | .byte '~,13,0 | ||
283 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
284 | .byte 0,0 | ||
285 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
286 | .byte 0,0,0,0 /* 36-39 */ | ||
287 | .fill 16,1,0 /* 3A-49 */ | ||
288 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
289 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
290 | .byte '| | ||
291 | .fill 10,1,0 | ||
292 | |||
293 | #elif defined(KBD_US) | ||
294 | |||
295 | key_map: | ||
296 | .byte 0,27 | ||
297 | .ascii "1234567890-=" | ||
298 | .byte 127,9 | ||
299 | .ascii "qwertyuiop[]" | ||
300 | .byte 13,0 | ||
301 | .ascii "asdfghjkl;'" | ||
302 | .byte '`,0 | ||
303 | .ascii "\\zxcvbnm,./" | ||
304 | .byte 0,'*,0,32 /* 36-39 */ | ||
305 | .fill 16,1,0 /* 3A-49 */ | ||
306 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
307 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
308 | .byte '< | ||
309 | .fill 10,1,0 | ||
310 | |||
311 | |||
312 | shift_map: | ||
313 | .byte 0,27 | ||
314 | .ascii "!@#$%^&*()_+" | ||
315 | .byte 127,9 | ||
316 | .ascii "QWERTYUIOP{}" | ||
317 | .byte 13,0 | ||
318 | .ascii "ASDFGHJKL:\"" | ||
319 | .byte '~,0 | ||
320 | .ascii "|ZXCVBNM<>?" | ||
321 | .byte 0,'*,0,32 /* 36-39 */ | ||
322 | .fill 16,1,0 /* 3A-49 */ | ||
323 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
324 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
325 | .byte '> | ||
326 | .fill 10,1,0 | ||
327 | |||
328 | alt_map: | ||
329 | .byte 0,0 | ||
330 | .ascii "\0@\0$\0\0{[]}\\\0" | ||
331 | .byte 0,0 | ||
332 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
333 | .byte '~,13,0 | ||
334 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
335 | .byte 0,0 | ||
336 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
337 | .byte 0,0,0,0 /* 36-39 */ | ||
338 | .fill 16,1,0 /* 3A-49 */ | ||
339 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
340 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
341 | .byte '| | ||
342 | .fill 10,1,0 | ||
343 | |||
344 | #elif defined(KBD_GR) | ||
345 | |||
346 | key_map: | ||
347 | .byte 0,27 | ||
348 | .ascii "1234567890\\'" | ||
349 | .byte 127,9 | ||
350 | .ascii "qwertzuiop@+" | ||
351 | .byte 13,0 | ||
352 | .ascii "asdfghjkl[]^" | ||
353 | .byte 0,'# | ||
354 | .ascii "yxcvbnm,.-" | ||
355 | .byte 0,'*,0,32 /* 36-39 */ | ||
356 | .fill 16,1,0 /* 3A-49 */ | ||
357 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
358 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
359 | .byte '< | ||
360 | .fill 10,1,0 | ||
361 | |||
362 | |||
363 | shift_map: | ||
364 | .byte 0,27 | ||
365 | .ascii "!\"#$%&/()=?`" | ||
366 | .byte 127,9 | ||
367 | .ascii "QWERTZUIOP\\*" | ||
368 | .byte 13,0 | ||
369 | .ascii "ASDFGHJKL{}~" | ||
370 | .byte 0,'' | ||
371 | .ascii "YXCVBNM;:_" | ||
372 | .byte 0,'*,0,32 /* 36-39 */ | ||
373 | .fill 16,1,0 /* 3A-49 */ | ||
374 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
375 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
376 | .byte '> | ||
377 | .fill 10,1,0 | ||
378 | |||
379 | alt_map: | ||
380 | .byte 0,0 | ||
381 | .ascii "\0@\0$\0\0{[]}\\\0" | ||
382 | .byte 0,0 | ||
383 | .byte '@,0,0,0,0,0,0,0,0,0,0 | ||
384 | .byte '~,13,0 | ||
385 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
386 | .byte 0,0 | ||
387 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
388 | .byte 0,0,0,0 /* 36-39 */ | ||
389 | .fill 16,1,0 /* 3A-49 */ | ||
390 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
391 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
392 | .byte '| | ||
393 | .fill 10,1,0 | ||
394 | |||
395 | |||
396 | #elif defined(KBD_FR) | ||
397 | |||
398 | key_map: | ||
399 | .byte 0,27 | ||
400 | .ascii "&{\"'(-}_/@)=" | ||
401 | .byte 127,9 | ||
402 | .ascii "azertyuiop^$" | ||
403 | .byte 13,0 | ||
404 | .ascii "qsdfghjklm|" | ||
405 | .byte '`,0,42 /* coin sup gauche, don't know, [*|mu] */ | ||
406 | .ascii "wxcvbn,;:!" | ||
407 | .byte 0,'*,0,32 /* 36-39 */ | ||
408 | .fill 16,1,0 /* 3A-49 */ | ||
409 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
410 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
411 | .byte '< | ||
412 | .fill 10,1,0 | ||
413 | |||
414 | shift_map: | ||
415 | .byte 0,27 | ||
416 | .ascii "1234567890]+" | ||
417 | .byte 127,9 | ||
418 | .ascii "AZERTYUIOP<>" | ||
419 | .byte 13,0 | ||
420 | .ascii "QSDFGHJKLM%" | ||
421 | .byte '~,0,'# | ||
422 | .ascii "WXCVBN?./\\" | ||
423 | .byte 0,'*,0,32 /* 36-39 */ | ||
424 | .fill 16,1,0 /* 3A-49 */ | ||
425 | .byte '-,0,0,0,'+ /* 4A-4E */ | ||
426 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
427 | .byte '> | ||
428 | .fill 10,1,0 | ||
429 | |||
430 | alt_map: | ||
431 | .byte 0,0 | ||
432 | .ascii "\0~#{[|`\\^@]}" | ||
433 | .byte 0,0 | ||
434 | .byte '@,0,0,0,0,0,0,0,0,0,0 | ||
435 | .byte '~,13,0 | ||
436 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
437 | .byte 0,0 | ||
438 | .byte 0,0,0,0,0,0,0,0,0,0,0 | ||
439 | .byte 0,0,0,0 /* 36-39 */ | ||
440 | .fill 16,1,0 /* 3A-49 */ | ||
441 | .byte 0,0,0,0,0 /* 4A-4E */ | ||
442 | .byte 0,0,0,0,0,0,0 /* 4F-55 */ | ||
443 | .byte '| | ||
444 | .fill 10,1,0 | ||
445 | |||
446 | #else | ||
447 | #error "KBD-type not defined" | ||
448 | #endif | ||
449 | /* | ||
450 | * do_self handles "normal" keys, ie keys that don't change meaning | ||
451 | * and which have just one character returns. | ||
452 | */ | ||
453 | do_self: | ||
454 | lea alt_map,%ebx | ||
455 | testb $0x20,mode /* alt-gr */ | ||
456 | jne 1f | ||
457 | lea shift_map,%ebx | ||
458 | testb $0x03,mode | ||
459 | jne 1f | ||
460 | lea key_map,%ebx | ||
461 | 1: movb (%ebx,%eax),%al | ||
462 | orb %al,%al | ||
463 | je none | ||
464 | testb $0x4c,mode /* ctrl or caps */ | ||
465 | je 2f | ||
466 | cmpb $'a,%al | ||
467 | jb 2f | ||
468 | cmpb $'},%al | ||
469 | ja 2f | ||
470 | subb $32,%al | ||
471 | 2: testb $0x0c,mode /* ctrl */ | ||
472 | je 3f | ||
473 | cmpb $64,%al | ||
474 | jb 3f | ||
475 | cmpb $64+32,%al | ||
476 | jae 3f | ||
477 | subb $64,%al | ||
478 | 3: testb $0x10,mode /* left alt */ | ||
479 | je 4f | ||
480 | orb $0x80,%al | ||
481 | 4: andl $0xff,%eax | ||
482 | xorl %ebx,%ebx | ||
483 | call put_queue | ||
484 | none: ret | ||
485 | |||
486 | /* | ||
487 | * minus has a routine of it's own, as a 'E0h' before | ||
488 | * the scan code for minus means that the numeric keypad | ||
489 | * slash was pushed. | ||
490 | */ | ||
491 | minus: cmpb $1,e0 | ||
492 | jne do_self | ||
493 | movl $'/,%eax | ||
494 | xorl %ebx,%ebx | ||
495 | jmp put_queue | ||
496 | |||
497 | /* | ||
498 | * This table decides which routine to call when a scan-code has been | ||
499 | * gotten. Most routines just call do_self, or none, depending if | ||
500 | * they are make or break. | ||
501 | */ | ||
502 | key_table: | ||
503 | .long none,do_self,do_self,do_self /* 00-03 s0 esc 1 2 */ | ||
504 | .long do_self,do_self,do_self,do_self /* 04-07 3 4 5 6 */ | ||
505 | .long do_self,do_self,do_self,do_self /* 08-0B 7 8 9 0 */ | ||
506 | .long do_self,do_self,do_self,do_self /* 0C-0F + ' bs tab */ | ||
507 | .long do_self,do_self,do_self,do_self /* 10-13 q w e r */ | ||
508 | .long do_self,do_self,do_self,do_self /* 14-17 t y u i */ | ||
509 | .long do_self,do_self,do_self,do_self /* 18-1B o p } ^ */ | ||
510 | .long do_self,ctrl,do_self,do_self /* 1C-1F enter ctrl a s */ | ||
511 | .long do_self,do_self,do_self,do_self /* 20-23 d f g h */ | ||
512 | .long do_self,do_self,do_self,do_self /* 24-27 j k l | */ | ||
513 | .long do_self,do_self,lshift,do_self /* 28-2B { para lshift , */ | ||
514 | .long do_self,do_self,do_self,do_self /* 2C-2F z x c v */ | ||
515 | .long do_self,do_self,do_self,do_self /* 30-33 b n m , */ | ||
516 | .long do_self,minus,rshift,do_self /* 34-37 . - rshift * */ | ||
517 | .long alt,do_self,caps,func /* 38-3B alt sp caps f1 */ | ||
518 | .long func,func,func,func /* 3C-3F f2 f3 f4 f5 */ | ||
519 | .long func,func,func,func /* 40-43 f6 f7 f8 f9 */ | ||
520 | .long func,num,scroll,cursor /* 44-47 f10 num scr home */ | ||
521 | .long cursor,cursor,do_self,cursor /* 48-4B up pgup - left */ | ||
522 | .long cursor,cursor,do_self,cursor /* 4C-4F n5 right + end */ | ||
523 | .long cursor,cursor,cursor,cursor /* 50-53 dn pgdn ins del */ | ||
524 | .long none,none,do_self,func /* 54-57 sysreq ? < f11 */ | ||
525 | .long func,none,none,none /* 58-5B f12 ? ? ? */ | ||
526 | .long none,none,none,none /* 5C-5F ? ? ? ? */ | ||
527 | .long none,none,none,none /* 60-63 ? ? ? ? */ | ||
528 | .long none,none,none,none /* 64-67 ? ? ? ? */ | ||
529 | .long none,none,none,none /* 68-6B ? ? ? ? */ | ||
530 | .long none,none,none,none /* 6C-6F ? ? ? ? */ | ||
531 | .long none,none,none,none /* 70-73 ? ? ? ? */ | ||
532 | .long none,none,none,none /* 74-77 ? ? ? ? */ | ||
533 | .long none,none,none,none /* 78-7B ? ? ? ? */ | ||
534 | .long none,none,none,none /* 7C-7F ? ? ? ? */ | ||
535 | .long none,none,none,none /* 80-83 ? br br br */ | ||
536 | .long none,none,none,none /* 84-87 br br br br */ | ||
537 | .long none,none,none,none /* 88-8B br br br br */ | ||
538 | .long none,none,none,none /* 8C-8F br br br br */ | ||
539 | .long none,none,none,none /* 90-93 br br br br */ | ||
540 | .long none,none,none,none /* 94-97 br br br br */ | ||
541 | .long none,none,none,none /* 98-9B br br br br */ | ||
542 | .long none,unctrl,none,none /* 9C-9F br unctrl br br */ | ||
543 | .long none,none,none,none /* A0-A3 br br br br */ | ||
544 | .long none,none,none,none /* A4-A7 br br br br */ | ||
545 | .long none,none,unlshift,none /* A8-AB br br unlshift br */ | ||
546 | .long none,none,none,none /* AC-AF br br br br */ | ||
547 | .long none,none,none,none /* B0-B3 br br br br */ | ||
548 | .long none,none,unrshift,none /* B4-B7 br br unrshift br */ | ||
549 | .long unalt,none,uncaps,none /* B8-BB unalt br uncaps br */ | ||
550 | .long none,none,none,none /* BC-BF br br br br */ | ||
551 | .long none,none,none,none /* C0-C3 br br br br */ | ||
552 | .long none,none,none,none /* C4-C7 br br br br */ | ||
553 | .long none,none,none,none /* C8-CB br br br br */ | ||
554 | .long none,none,none,none /* CC-CF br br br br */ | ||
555 | .long none,none,none,none /* D0-D3 br br br br */ | ||
556 | .long none,none,none,none /* D4-D7 br br br br */ | ||
557 | .long none,none,none,none /* D8-DB br ? ? ? */ | ||
558 | .long none,none,none,none /* DC-DF ? ? ? ? */ | ||
559 | .long none,none,none,none /* E0-E3 e0 e1 ? ? */ | ||
560 | .long none,none,none,none /* E4-E7 ? ? ? ? */ | ||
561 | .long none,none,none,none /* E8-EB ? ? ? ? */ | ||
562 | .long none,none,none,none /* EC-EF ? ? ? ? */ | ||
563 | .long none,none,none,none /* F0-F3 ? ? ? ? */ | ||
564 | .long none,none,none,none /* F4-F7 ? ? ? ? */ | ||
565 | .long none,none,none,none /* F8-FB ? ? ? ? */ | ||
566 | .long none,none,none,none /* FC-FF ? ? ? ? */ | ||
567 | |||
568 | /* | ||
569 | * kb_wait waits for the keyboard controller buffer to empty. | ||
570 | * there is no timeout - if the buffer doesn't empty, we hang. | ||
571 | */ | ||
572 | kb_wait: | ||
573 | pushl %eax | ||
574 | 1: inb $0x64,%al | ||
575 | testb $0x02,%al | ||
576 | jne 1b | ||
577 | popl %eax | ||
578 | ret | ||
579 | /* | ||
580 | * This routine reboots the machine by asking the keyboard | ||
581 | * controller to pulse the reset-line low. | ||
582 | */ | ||
583 | reboot: | ||
584 | call kb_wait | ||
585 | movw $0x1234,0x472 /* don't do memory check */ | ||
586 | movb $0xfc,%al /* pulse reset and A20 low */ | ||
587 | outb %al,$0x64 | ||
588 | die: jmp die | ||
diff --git a/src/kernel/chr_drv/rs_io.s b/src/kernel/chr_drv/rs_io.s new file mode 100644 index 0000000..6788658 --- /dev/null +++ b/src/kernel/chr_drv/rs_io.s | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * linux/kernel/rs_io.s | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * rs_io.s | ||
9 | * | ||
10 | * This module implements the rs232 io interrupts. | ||
11 | */ | ||
12 | |||
13 | .text | ||
14 | .globl rs1_interrupt,rs2_interrupt | ||
15 | |||
16 | size = 1024 /* must be power of two ! | ||
17 | and must match the value | ||
18 | in tty_io.c!!! */ | ||
19 | |||
20 | /* these are the offsets into the read/write buffer structures */ | ||
21 | rs_addr = 0 | ||
22 | head = 4 | ||
23 | tail = 8 | ||
24 | proc_list = 12 | ||
25 | buf = 16 | ||
26 | |||
27 | startup = 256 /* chars left in write queue when we restart it */ | ||
28 | |||
29 | /* | ||
30 | * These are the actual interrupt routines. They look where | ||
31 | * the interrupt is coming from, and take appropriate action. | ||
32 | */ | ||
33 | .align 2 | ||
34 | rs1_interrupt: | ||
35 | pushl $table_list+8 | ||
36 | jmp rs_int | ||
37 | .align 2 | ||
38 | rs2_interrupt: | ||
39 | pushl $table_list+16 | ||
40 | rs_int: | ||
41 | pushl %edx | ||
42 | pushl %ecx | ||
43 | pushl %ebx | ||
44 | pushl %eax | ||
45 | push %es | ||
46 | push %ds /* as this is an interrupt, we cannot */ | ||
47 | pushl $0x10 /* know that bs is ok. Load it */ | ||
48 | pop %ds | ||
49 | pushl $0x10 | ||
50 | pop %es | ||
51 | movl 24(%esp),%edx | ||
52 | movl (%edx),%edx | ||
53 | movl rs_addr(%edx),%edx | ||
54 | addl $2,%edx /* interrupt ident. reg */ | ||
55 | rep_int: | ||
56 | xorl %eax,%eax | ||
57 | inb %dx,%al | ||
58 | testb $1,%al | ||
59 | jne end | ||
60 | cmpb $6,%al /* this shouldn't happen, but ... */ | ||
61 | ja end | ||
62 | movl 24(%esp),%ecx | ||
63 | pushl %edx | ||
64 | subl $2,%edx | ||
65 | call *jmp_table(,%eax,2) /* NOTE! not *4, bit0 is 0 already */ | ||
66 | popl %edx | ||
67 | jmp rep_int | ||
68 | end: movb $0x20,%al | ||
69 | outb %al,$0x20 /* EOI */ | ||
70 | pop %ds | ||
71 | pop %es | ||
72 | popl %eax | ||
73 | popl %ebx | ||
74 | popl %ecx | ||
75 | popl %edx | ||
76 | addl $4,%esp # jump over _table_list entry | ||
77 | iret | ||
78 | |||
79 | jmp_table: | ||
80 | .long modem_status,write_char,read_char,line_status | ||
81 | |||
82 | .align 2 | ||
83 | modem_status: | ||
84 | addl $6,%edx /* clear intr by reading modem status reg */ | ||
85 | inb %dx,%al | ||
86 | ret | ||
87 | |||
88 | .align 2 | ||
89 | line_status: | ||
90 | addl $5,%edx /* clear intr by reading line status reg. */ | ||
91 | inb %dx,%al | ||
92 | ret | ||
93 | |||
94 | .align 2 | ||
95 | read_char: | ||
96 | inb %dx,%al | ||
97 | movl %ecx,%edx | ||
98 | subl $table_list,%edx | ||
99 | shrl $3,%edx | ||
100 | movl (%ecx),%ecx # read-queue | ||
101 | movl head(%ecx),%ebx | ||
102 | movb %al,buf(%ecx,%ebx) | ||
103 | incl %ebx | ||
104 | andl $size-1,%ebx | ||
105 | cmpl tail(%ecx),%ebx | ||
106 | je 1f | ||
107 | movl %ebx,head(%ecx) | ||
108 | 1: pushl %edx | ||
109 | call do_tty_interrupt | ||
110 | addl $4,%esp | ||
111 | ret | ||
112 | |||
113 | .align 2 | ||
114 | write_char: | ||
115 | movl 4(%ecx),%ecx # write-queue | ||
116 | movl head(%ecx),%ebx | ||
117 | subl tail(%ecx),%ebx | ||
118 | andl $size-1,%ebx # nr chars in queue | ||
119 | je write_buffer_empty | ||
120 | cmpl $startup,%ebx | ||
121 | ja 1f | ||
122 | movl proc_list(%ecx),%ebx # wake up sleeping process | ||
123 | testl %ebx,%ebx # is there any? | ||
124 | je 1f | ||
125 | movl $0,(%ebx) | ||
126 | 1: movl tail(%ecx),%ebx | ||
127 | movb buf(%ecx,%ebx),%al | ||
128 | outb %al,%dx | ||
129 | incl %ebx | ||
130 | andl $size-1,%ebx | ||
131 | movl %ebx,tail(%ecx) | ||
132 | cmpl head(%ecx),%ebx | ||
133 | je write_buffer_empty | ||
134 | ret | ||
135 | .align 2 | ||
136 | write_buffer_empty: | ||
137 | movl proc_list(%ecx),%ebx # wake up sleeping process | ||
138 | testl %ebx,%ebx # is there any? | ||
139 | je 1f | ||
140 | movl $0,(%ebx) | ||
141 | 1: incl %edx | ||
142 | inb %dx,%al | ||
143 | jmp 1f | ||
144 | 1: jmp 1f | ||
145 | 1: andb $0xd,%al /* disable transmit interrupt */ | ||
146 | outb %al,%dx | ||
147 | ret | ||
diff --git a/src/kernel/chr_drv/serial.c b/src/kernel/chr_drv/serial.c new file mode 100644 index 0000000..aba25df --- /dev/null +++ b/src/kernel/chr_drv/serial.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * linux/kernel/serial.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * serial.c | ||
9 | * | ||
10 | * This module implements the rs232 io functions | ||
11 | * void rs_write(struct tty_struct * queue); | ||
12 | * void rs_init(void); | ||
13 | * and all interrupts pertaining to serial IO. | ||
14 | */ | ||
15 | |||
16 | #include <linux/tty.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <asm/system.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | #define WAKEUP_CHARS (TTY_BUF_SIZE/4) | ||
22 | |||
23 | extern void rs1_interrupt(void); | ||
24 | extern void rs2_interrupt(void); | ||
25 | |||
26 | static void init(int port) | ||
27 | { | ||
28 | outb_p(0x80,port+3); /* set DLAB of line control reg */ | ||
29 | outb_p(0x30,port); /* LS of divisor (48 -> 2400 bps */ | ||
30 | outb_p(0x00,port+1); /* MS of divisor */ | ||
31 | outb_p(0x03,port+3); /* reset DLAB */ | ||
32 | outb_p(0x0b,port+4); /* set DTR,RTS, OUT_2 */ | ||
33 | outb_p(0x0d,port+1); /* enable all intrs but writes */ | ||
34 | (void)inb(port); /* read data port to reset things (?) */ | ||
35 | } | ||
36 | |||
37 | void rs_init(void) | ||
38 | { | ||
39 | set_intr_gate(0x24,rs1_interrupt); | ||
40 | set_intr_gate(0x23,rs2_interrupt); | ||
41 | init(tty_table[1].read_q.data); | ||
42 | init(tty_table[2].read_q.data); | ||
43 | outb(inb_p(0x21)&0xE7,0x21); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * This routine gets called when tty_write has put something into | ||
48 | * the write_queue. It must check wheter the queue is empty, and | ||
49 | * set the interrupt register accordingly | ||
50 | * | ||
51 | * void _rs_write(struct tty_struct * tty); | ||
52 | */ | ||
53 | void rs_write(struct tty_struct * tty) | ||
54 | { | ||
55 | cli(); | ||
56 | if (!EMPTY(tty->write_q)) | ||
57 | outb(inb_p(tty->write_q.data+1)|0x02,tty->write_q.data+1); | ||
58 | sti(); | ||
59 | } | ||
diff --git a/src/kernel/chr_drv/tty_io.c b/src/kernel/chr_drv/tty_io.c new file mode 100644 index 0000000..ed14fa8 --- /dev/null +++ b/src/kernel/chr_drv/tty_io.c | |||
@@ -0,0 +1,350 @@ | |||
1 | /* | ||
2 | * linux/kernel/tty_io.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles | ||
9 | * or rs-channels. It also implements echoing, cooked mode etc. | ||
10 | * | ||
11 | * Kill-line thanks to John T Kohl. | ||
12 | */ | ||
13 | #include <ctype.h> | ||
14 | #include <errno.h> | ||
15 | #include <signal.h> | ||
16 | |||
17 | #define ALRMMASK (1<<(SIGALRM-1)) | ||
18 | #define KILLMASK (1<<(SIGKILL-1)) | ||
19 | #define INTMASK (1<<(SIGINT-1)) | ||
20 | #define QUITMASK (1<<(SIGQUIT-1)) | ||
21 | #define TSTPMASK (1<<(SIGTSTP-1)) | ||
22 | |||
23 | #include <linux/sched.h> | ||
24 | #include <linux/tty.h> | ||
25 | #include <asm/segment.h> | ||
26 | #include <asm/system.h> | ||
27 | |||
28 | #define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f) | ||
29 | #define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f) | ||
30 | #define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f) | ||
31 | |||
32 | #define L_CANON(tty) _L_FLAG((tty),ICANON) | ||
33 | #define L_ISIG(tty) _L_FLAG((tty),ISIG) | ||
34 | #define L_ECHO(tty) _L_FLAG((tty),ECHO) | ||
35 | #define L_ECHOE(tty) _L_FLAG((tty),ECHOE) | ||
36 | #define L_ECHOK(tty) _L_FLAG((tty),ECHOK) | ||
37 | #define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) | ||
38 | #define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) | ||
39 | |||
40 | #define I_UCLC(tty) _I_FLAG((tty),IUCLC) | ||
41 | #define I_NLCR(tty) _I_FLAG((tty),INLCR) | ||
42 | #define I_CRNL(tty) _I_FLAG((tty),ICRNL) | ||
43 | #define I_NOCR(tty) _I_FLAG((tty),IGNCR) | ||
44 | |||
45 | #define O_POST(tty) _O_FLAG((tty),OPOST) | ||
46 | #define O_NLCR(tty) _O_FLAG((tty),ONLCR) | ||
47 | #define O_CRNL(tty) _O_FLAG((tty),OCRNL) | ||
48 | #define O_NLRET(tty) _O_FLAG((tty),ONLRET) | ||
49 | #define O_LCUC(tty) _O_FLAG((tty),OLCUC) | ||
50 | |||
51 | struct tty_struct tty_table[] = { | ||
52 | { | ||
53 | {ICRNL, /* change incoming CR to NL */ | ||
54 | OPOST|ONLCR, /* change outgoing NL to CRNL */ | ||
55 | 0, | ||
56 | ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, | ||
57 | 0, /* console termio */ | ||
58 | INIT_C_CC}, | ||
59 | 0, /* initial pgrp */ | ||
60 | 0, /* initial stopped */ | ||
61 | con_write, | ||
62 | {0,0,0,0,""}, /* console read-queue */ | ||
63 | {0,0,0,0,""}, /* console write-queue */ | ||
64 | {0,0,0,0,""} /* console secondary queue */ | ||
65 | },{ | ||
66 | {0, /* no translation */ | ||
67 | 0, /* no translation */ | ||
68 | B2400 | CS8, | ||
69 | 0, | ||
70 | 0, | ||
71 | INIT_C_CC}, | ||
72 | 0, | ||
73 | 0, | ||
74 | rs_write, | ||
75 | {0x3f8,0,0,0,""}, /* rs 1 */ | ||
76 | {0x3f8,0,0,0,""}, | ||
77 | {0,0,0,0,""} | ||
78 | },{ | ||
79 | {0, /* no translation */ | ||
80 | 0, /* no translation */ | ||
81 | B2400 | CS8, | ||
82 | 0, | ||
83 | 0, | ||
84 | INIT_C_CC}, | ||
85 | 0, | ||
86 | 0, | ||
87 | rs_write, | ||
88 | {0x2f8,0,0,0,""}, /* rs 2 */ | ||
89 | {0x2f8,0,0,0,""}, | ||
90 | {0,0,0,0,""} | ||
91 | } | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * these are the tables used by the machine code handlers. | ||
96 | * you can implement pseudo-tty's or something by changing | ||
97 | * them. Currently not done. | ||
98 | */ | ||
99 | struct tty_queue * table_list[]={ | ||
100 | &tty_table[0].read_q, &tty_table[0].write_q, | ||
101 | &tty_table[1].read_q, &tty_table[1].write_q, | ||
102 | &tty_table[2].read_q, &tty_table[2].write_q | ||
103 | }; | ||
104 | |||
105 | void tty_init(void) | ||
106 | { | ||
107 | rs_init(); | ||
108 | con_init(); | ||
109 | } | ||
110 | |||
111 | void tty_intr(struct tty_struct * tty, int mask) | ||
112 | { | ||
113 | int i; | ||
114 | |||
115 | if (tty->pgrp <= 0) | ||
116 | return; | ||
117 | for (i=0;i<NR_TASKS;i++) | ||
118 | if (task[i] && task[i]->pgrp==tty->pgrp) | ||
119 | task[i]->signal |= mask; | ||
120 | } | ||
121 | |||
122 | static void sleep_if_empty(struct tty_queue * queue) | ||
123 | { | ||
124 | cli(); | ||
125 | while (!current->signal && EMPTY(*queue)) | ||
126 | interruptible_sleep_on(&queue->proc_list); | ||
127 | sti(); | ||
128 | } | ||
129 | |||
130 | static void sleep_if_full(struct tty_queue * queue) | ||
131 | { | ||
132 | if (!FULL(*queue)) | ||
133 | return; | ||
134 | cli(); | ||
135 | while (!current->signal && LEFT(*queue)<128) | ||
136 | interruptible_sleep_on(&queue->proc_list); | ||
137 | sti(); | ||
138 | } | ||
139 | |||
140 | void wait_for_keypress(void) | ||
141 | { | ||
142 | sleep_if_empty(&tty_table[0].secondary); | ||
143 | } | ||
144 | |||
145 | void copy_to_cooked(struct tty_struct * tty) | ||
146 | { | ||
147 | signed char c; | ||
148 | |||
149 | while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) { | ||
150 | GETCH(tty->read_q,c); | ||
151 | if (c==13) | ||
152 | if (I_CRNL(tty)) | ||
153 | c=10; | ||
154 | else if (I_NOCR(tty)) | ||
155 | continue; | ||
156 | else ; | ||
157 | else if (c==10 && I_NLCR(tty)) | ||
158 | c=13; | ||
159 | if (I_UCLC(tty)) | ||
160 | c=tolower(c); | ||
161 | if (L_CANON(tty)) { | ||
162 | if (c==KILL_CHAR(tty)) { | ||
163 | /* deal with killing the input line */ | ||
164 | while(!(EMPTY(tty->secondary) || | ||
165 | (c=LAST(tty->secondary))==10 || | ||
166 | c==EOF_CHAR(tty))) { | ||
167 | if (L_ECHO(tty)) { | ||
168 | if (c<32) | ||
169 | PUTCH(127,tty->write_q); | ||
170 | PUTCH(127,tty->write_q); | ||
171 | tty->write(tty); | ||
172 | } | ||
173 | DEC(tty->secondary.head); | ||
174 | } | ||
175 | continue; | ||
176 | } | ||
177 | if (c==ERASE_CHAR(tty)) { | ||
178 | if (EMPTY(tty->secondary) || | ||
179 | (c=LAST(tty->secondary))==10 || | ||
180 | c==EOF_CHAR(tty)) | ||
181 | continue; | ||
182 | if (L_ECHO(tty)) { | ||
183 | if (c<32) | ||
184 | PUTCH(127,tty->write_q); | ||
185 | PUTCH(127,tty->write_q); | ||
186 | tty->write(tty); | ||
187 | } | ||
188 | DEC(tty->secondary.head); | ||
189 | continue; | ||
190 | } | ||
191 | if (c==STOP_CHAR(tty)) { | ||
192 | tty->stopped=1; | ||
193 | continue; | ||
194 | } | ||
195 | if (c==START_CHAR(tty)) { | ||
196 | tty->stopped=0; | ||
197 | continue; | ||
198 | } | ||
199 | } | ||
200 | if (L_ISIG(tty)) { | ||
201 | if (c==INTR_CHAR(tty)) { | ||
202 | tty_intr(tty,INTMASK); | ||
203 | continue; | ||
204 | } | ||
205 | if (c==QUIT_CHAR(tty)) { | ||
206 | tty_intr(tty,QUITMASK); | ||
207 | continue; | ||
208 | } | ||
209 | } | ||
210 | if (c==10 || c==EOF_CHAR(tty)) | ||
211 | tty->secondary.data++; | ||
212 | if (L_ECHO(tty)) { | ||
213 | if (c==10) { | ||
214 | PUTCH(10,tty->write_q); | ||
215 | PUTCH(13,tty->write_q); | ||
216 | } else if (c<32) { | ||
217 | if (L_ECHOCTL(tty)) { | ||
218 | PUTCH('^',tty->write_q); | ||
219 | PUTCH(c+64,tty->write_q); | ||
220 | } | ||
221 | } else | ||
222 | PUTCH(c,tty->write_q); | ||
223 | tty->write(tty); | ||
224 | } | ||
225 | PUTCH(c,tty->secondary); | ||
226 | } | ||
227 | wake_up(&tty->secondary.proc_list); | ||
228 | } | ||
229 | |||
230 | int tty_read(unsigned channel, char * buf, int nr) | ||
231 | { | ||
232 | struct tty_struct * tty; | ||
233 | char c, * b=buf; | ||
234 | int minimum,time,flag=0; | ||
235 | long oldalarm; | ||
236 | |||
237 | if (channel>2 || nr<0) return -1; | ||
238 | tty = &tty_table[channel]; | ||
239 | oldalarm = current->alarm; | ||
240 | time = 10L*tty->termios.c_cc[VTIME]; | ||
241 | minimum = tty->termios.c_cc[VMIN]; | ||
242 | if (time && !minimum) { | ||
243 | minimum=1; | ||
244 | if ((flag=(!oldalarm || time+jiffies<oldalarm))) | ||
245 | current->alarm = time+jiffies; | ||
246 | } | ||
247 | if (minimum>nr) | ||
248 | minimum=nr; | ||
249 | while (nr>0) { | ||
250 | if (flag && (current->signal & ALRMMASK)) { | ||
251 | current->signal &= ~ALRMMASK; | ||
252 | break; | ||
253 | } | ||
254 | if (current->signal) | ||
255 | break; | ||
256 | if (EMPTY(tty->secondary) || (L_CANON(tty) && | ||
257 | !tty->secondary.data && LEFT(tty->secondary)>20)) { | ||
258 | sleep_if_empty(&tty->secondary); | ||
259 | continue; | ||
260 | } | ||
261 | do { | ||
262 | GETCH(tty->secondary,c); | ||
263 | if (c==EOF_CHAR(tty) || c==10) | ||
264 | tty->secondary.data--; | ||
265 | if (c==EOF_CHAR(tty) && L_CANON(tty)) | ||
266 | return (b-buf); | ||
267 | else { | ||
268 | put_fs_byte(c,b++); | ||
269 | if (!--nr) | ||
270 | break; | ||
271 | } | ||
272 | } while (nr>0 && !EMPTY(tty->secondary)); | ||
273 | if (time && !L_CANON(tty)) { | ||
274 | if ((flag=(!oldalarm || time+jiffies<oldalarm))) | ||
275 | current->alarm = time+jiffies; | ||
276 | else | ||
277 | current->alarm = oldalarm; | ||
278 | } | ||
279 | if (L_CANON(tty)) { | ||
280 | if (b-buf) | ||
281 | break; | ||
282 | } else if (b-buf >= minimum) | ||
283 | break; | ||
284 | } | ||
285 | current->alarm = oldalarm; | ||
286 | if (current->signal && !(b-buf)) | ||
287 | return -EINTR; | ||
288 | return (b-buf); | ||
289 | } | ||
290 | |||
291 | int tty_write(unsigned channel, char * buf, int nr) | ||
292 | { | ||
293 | static int cr_flag=0; | ||
294 | struct tty_struct * tty; | ||
295 | char c, *b=buf; | ||
296 | |||
297 | if (channel>2 || nr<0) return -1; | ||
298 | tty = channel + tty_table; | ||
299 | while (nr>0) { | ||
300 | sleep_if_full(&tty->write_q); | ||
301 | if (current->signal) | ||
302 | break; | ||
303 | while (nr>0 && !FULL(tty->write_q)) { | ||
304 | c=get_fs_byte(b); | ||
305 | if (O_POST(tty)) { | ||
306 | if (c=='\r' && O_CRNL(tty)) | ||
307 | c='\n'; | ||
308 | else if (c=='\n' && O_NLRET(tty)) | ||
309 | c='\r'; | ||
310 | if (c=='\n' && !cr_flag && O_NLCR(tty)) { | ||
311 | cr_flag = 1; | ||
312 | PUTCH(13,tty->write_q); | ||
313 | continue; | ||
314 | } | ||
315 | if (O_LCUC(tty)) | ||
316 | c=toupper(c); | ||
317 | } | ||
318 | b++; nr--; | ||
319 | cr_flag = 0; | ||
320 | PUTCH(c,tty->write_q); | ||
321 | } | ||
322 | tty->write(tty); | ||
323 | if (nr>0) | ||
324 | schedule(); | ||
325 | } | ||
326 | return (b-buf); | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * Jeh, sometimes I really like the 386. | ||
331 | * This routine is called from an interrupt, | ||
332 | * and there should be absolutely no problem | ||
333 | * with sleeping even in an interrupt (I hope). | ||
334 | * Of course, if somebody proves me wrong, I'll | ||
335 | * hate intel for all time :-). We'll have to | ||
336 | * be careful and see to reinstating the interrupt | ||
337 | * chips before calling this, though. | ||
338 | * | ||
339 | * I don't think we sleep here under normal circumstances | ||
340 | * anyway, which is good, as the task sleeping might be | ||
341 | * totally innocent. | ||
342 | */ | ||
343 | void do_tty_interrupt(int tty) | ||
344 | { | ||
345 | copy_to_cooked(tty_table+tty); | ||
346 | } | ||
347 | |||
348 | void chr_dev_init(void) | ||
349 | { | ||
350 | } | ||
diff --git a/src/kernel/chr_drv/tty_ioctl.c b/src/kernel/chr_drv/tty_ioctl.c new file mode 100644 index 0000000..e4e3745 --- /dev/null +++ b/src/kernel/chr_drv/tty_ioctl.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * linux/kernel/chr_drv/tty_ioctl.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | #include <termios.h> | ||
9 | |||
10 | #include <linux/sched.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/tty.h> | ||
13 | |||
14 | #include <asm/io.h> | ||
15 | #include <asm/segment.h> | ||
16 | #include <asm/system.h> | ||
17 | |||
18 | static unsigned short quotient[] = { | ||
19 | 0, 2304, 1536, 1047, 857, | ||
20 | 768, 576, 384, 192, 96, | ||
21 | 64, 48, 24, 12, 6, 3 | ||
22 | }; | ||
23 | |||
24 | static void change_speed(struct tty_struct * tty) | ||
25 | { | ||
26 | unsigned short port,quot; | ||
27 | |||
28 | if (!(port = tty->read_q.data)) | ||
29 | return; | ||
30 | quot = quotient[tty->termios.c_cflag & CBAUD]; | ||
31 | cli(); | ||
32 | outb_p(0x80,port+3); /* set DLAB */ | ||
33 | outb_p(quot & 0xff,port); /* LS of divisor */ | ||
34 | outb_p(quot >> 8,port+1); /* MS of divisor */ | ||
35 | outb(0x03,port+3); /* reset DLAB */ | ||
36 | sti(); | ||
37 | } | ||
38 | |||
39 | static void flush(struct tty_queue * queue) | ||
40 | { | ||
41 | cli(); | ||
42 | queue->head = queue->tail; | ||
43 | sti(); | ||
44 | } | ||
45 | |||
46 | static void wait_until_sent(struct tty_struct * tty) | ||
47 | { | ||
48 | /* do nothing - not implemented */ | ||
49 | } | ||
50 | |||
51 | static void send_break(struct tty_struct * tty) | ||
52 | { | ||
53 | /* do nothing - not implemented */ | ||
54 | } | ||
55 | |||
56 | static int get_termios(struct tty_struct * tty, struct termios * termios) | ||
57 | { | ||
58 | int i; | ||
59 | |||
60 | verify_area(termios, sizeof (*termios)); | ||
61 | for (i=0 ; i< (sizeof (*termios)) ; i++) | ||
62 | put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios ); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int set_termios(struct tty_struct * tty, struct termios * termios) | ||
67 | { | ||
68 | int i; | ||
69 | |||
70 | for (i=0 ; i< (sizeof (*termios)) ; i++) | ||
71 | ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios); | ||
72 | change_speed(tty); | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int get_termio(struct tty_struct * tty, struct termio * termio) | ||
77 | { | ||
78 | int i; | ||
79 | struct termio tmp_termio; | ||
80 | |||
81 | verify_area(termio, sizeof (*termio)); | ||
82 | tmp_termio.c_iflag = tty->termios.c_iflag; | ||
83 | tmp_termio.c_oflag = tty->termios.c_oflag; | ||
84 | tmp_termio.c_cflag = tty->termios.c_cflag; | ||
85 | tmp_termio.c_lflag = tty->termios.c_lflag; | ||
86 | tmp_termio.c_line = tty->termios.c_line; | ||
87 | for(i=0 ; i < NCC ; i++) | ||
88 | tmp_termio.c_cc[i] = tty->termios.c_cc[i]; | ||
89 | for (i=0 ; i< (sizeof (*termio)) ; i++) | ||
90 | put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio ); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * This only works as the 386 is low-byt-first | ||
96 | */ | ||
97 | static int set_termio(struct tty_struct * tty, struct termio * termio) | ||
98 | { | ||
99 | int i; | ||
100 | struct termio tmp_termio; | ||
101 | |||
102 | for (i=0 ; i< (sizeof (*termio)) ; i++) | ||
103 | ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio); | ||
104 | *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag; | ||
105 | *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag; | ||
106 | *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag; | ||
107 | *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag; | ||
108 | tty->termios.c_line = tmp_termio.c_line; | ||
109 | for(i=0 ; i < NCC ; i++) | ||
110 | tty->termios.c_cc[i] = tmp_termio.c_cc[i]; | ||
111 | change_speed(tty); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | int tty_ioctl(int dev, int cmd, int arg) | ||
116 | { | ||
117 | struct tty_struct * tty; | ||
118 | if (MAJOR(dev) == 5) { | ||
119 | dev=current->tty; | ||
120 | if (dev<0) | ||
121 | panic("tty_ioctl: dev<0"); | ||
122 | } else | ||
123 | dev=MINOR(dev); | ||
124 | tty = dev + tty_table; | ||
125 | switch (cmd) { | ||
126 | case TCGETS: | ||
127 | return get_termios(tty,(struct termios *) arg); | ||
128 | case TCSETSF: | ||
129 | flush(&tty->read_q); /* fallthrough */ | ||
130 | case TCSETSW: | ||
131 | wait_until_sent(tty); /* fallthrough */ | ||
132 | case TCSETS: | ||
133 | return set_termios(tty,(struct termios *) arg); | ||
134 | case TCGETA: | ||
135 | return get_termio(tty,(struct termio *) arg); | ||
136 | case TCSETAF: | ||
137 | flush(&tty->read_q); /* fallthrough */ | ||
138 | case TCSETAW: | ||
139 | wait_until_sent(tty); /* fallthrough */ | ||
140 | case TCSETA: | ||
141 | return set_termio(tty,(struct termio *) arg); | ||
142 | case TCSBRK: | ||
143 | if (!arg) { | ||
144 | wait_until_sent(tty); | ||
145 | send_break(tty); | ||
146 | } | ||
147 | return 0; | ||
148 | case TCXONC: | ||
149 | return -EINVAL; /* not implemented */ | ||
150 | case TCFLSH: | ||
151 | if (arg==0) | ||
152 | flush(&tty->read_q); | ||
153 | else if (arg==1) | ||
154 | flush(&tty->write_q); | ||
155 | else if (arg==2) { | ||
156 | flush(&tty->read_q); | ||
157 | flush(&tty->write_q); | ||
158 | } else | ||
159 | return -EINVAL; | ||
160 | return 0; | ||
161 | case TIOCEXCL: | ||
162 | return -EINVAL; /* not implemented */ | ||
163 | case TIOCNXCL: | ||
164 | return -EINVAL; /* not implemented */ | ||
165 | case TIOCSCTTY: | ||
166 | return -EINVAL; /* set controlling term NI */ | ||
167 | case TIOCGPGRP: | ||
168 | verify_area((void *) arg,4); | ||
169 | put_fs_long(tty->pgrp,(unsigned long *) arg); | ||
170 | return 0; | ||
171 | case TIOCSPGRP: | ||
172 | tty->pgrp=get_fs_long((unsigned long *) arg); | ||
173 | return 0; | ||
174 | case TIOCOUTQ: | ||
175 | verify_area((void *) arg,4); | ||
176 | put_fs_long(CHARS(tty->write_q),(unsigned long *) arg); | ||
177 | return 0; | ||
178 | case TIOCINQ: | ||
179 | verify_area((void *) arg,4); | ||
180 | put_fs_long(CHARS(tty->secondary), | ||
181 | (unsigned long *) arg); | ||
182 | return 0; | ||
183 | case TIOCSTI: | ||
184 | return -EINVAL; /* not implemented */ | ||
185 | case TIOCGWINSZ: | ||
186 | return -EINVAL; /* not implemented */ | ||
187 | case TIOCSWINSZ: | ||
188 | return -EINVAL; /* not implemented */ | ||
189 | case TIOCMGET: | ||
190 | return -EINVAL; /* not implemented */ | ||
191 | case TIOCMBIS: | ||
192 | return -EINVAL; /* not implemented */ | ||
193 | case TIOCMBIC: | ||
194 | return -EINVAL; /* not implemented */ | ||
195 | case TIOCMSET: | ||
196 | return -EINVAL; /* not implemented */ | ||
197 | case TIOCGSOFTCAR: | ||
198 | return -EINVAL; /* not implemented */ | ||
199 | case TIOCSSOFTCAR: | ||
200 | return -EINVAL; /* not implemented */ | ||
201 | default: | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | } | ||
diff --git a/src/kernel/exit.c b/src/kernel/exit.c new file mode 100644 index 0000000..b22de34 --- /dev/null +++ b/src/kernel/exit.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * linux/kernel/exit.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | #include <signal.h> | ||
9 | #include <sys/wait.h> | ||
10 | |||
11 | #include <linux/sched.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/tty.h> | ||
14 | #include <asm/segment.h> | ||
15 | |||
16 | int sys_pause(void); | ||
17 | int sys_close(int fd); | ||
18 | |||
19 | void release(struct task_struct * p) | ||
20 | { | ||
21 | int i; | ||
22 | |||
23 | if (!p) | ||
24 | return; | ||
25 | for (i=1 ; i<NR_TASKS ; i++) | ||
26 | if (task[i]==p) { | ||
27 | task[i]=NULL; | ||
28 | free_page((long)p); | ||
29 | schedule(); | ||
30 | return; | ||
31 | } | ||
32 | panic("trying to release non-existent task"); | ||
33 | } | ||
34 | |||
35 | static inline int send_sig(long sig,struct task_struct * p,int priv) | ||
36 | { | ||
37 | if (!p || sig<1 || sig>32) | ||
38 | return -EINVAL; | ||
39 | if (priv || (current->euid==p->euid) || suser()) | ||
40 | p->signal |= (1<<(sig-1)); | ||
41 | else | ||
42 | return -EPERM; | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static void kill_session(void) | ||
47 | { | ||
48 | struct task_struct **p = NR_TASKS + task; | ||
49 | |||
50 | while (--p > &FIRST_TASK) { | ||
51 | if (*p && (*p)->session == current->session) | ||
52 | (*p)->signal |= 1<<(SIGHUP-1); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * XXX need to check permissions needed to send signals to process | ||
58 | * groups, etc. etc. kill() permissions semantics are tricky! | ||
59 | */ | ||
60 | int sys_kill(int pid,int sig) | ||
61 | { | ||
62 | struct task_struct **p = NR_TASKS + task; | ||
63 | int err, retval = 0; | ||
64 | |||
65 | if (!pid) while (--p > &FIRST_TASK) { | ||
66 | if (*p && (*p)->pgrp == current->pid) | ||
67 | if ((err=send_sig(sig,*p,1))) | ||
68 | retval = err; | ||
69 | } else if (pid>0) while (--p > &FIRST_TASK) { | ||
70 | if (*p && (*p)->pid == pid) | ||
71 | if ((err=send_sig(sig,*p,0))) | ||
72 | retval = err; | ||
73 | } else if (pid == -1) while (--p > &FIRST_TASK) { | ||
74 | if ((err = send_sig(sig,*p,0))) | ||
75 | retval = err; | ||
76 | } else while (--p > &FIRST_TASK) | ||
77 | if (*p && (*p)->pgrp == -pid) | ||
78 | if ((err = send_sig(sig,*p,0))) | ||
79 | retval = err; | ||
80 | return retval; | ||
81 | } | ||
82 | |||
83 | static void tell_father(int pid) | ||
84 | { | ||
85 | int i; | ||
86 | |||
87 | if (pid) | ||
88 | for (i=0;i<NR_TASKS;i++) { | ||
89 | if (!task[i]) | ||
90 | continue; | ||
91 | if (task[i]->pid != pid) | ||
92 | continue; | ||
93 | task[i]->signal |= (1<<(SIGCHLD-1)); | ||
94 | return; | ||
95 | } | ||
96 | /* if we don't find any fathers, we just release ourselves */ | ||
97 | /* This is not really OK. Must change it to make father 1 */ | ||
98 | printk("BAD BAD - no father found\n\r"); | ||
99 | release(current); | ||
100 | } | ||
101 | |||
102 | int do_exit(long code) | ||
103 | { | ||
104 | int i; | ||
105 | free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); | ||
106 | free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); | ||
107 | for (i=0 ; i<NR_TASKS ; i++) | ||
108 | if (task[i] && task[i]->father == current->pid) { | ||
109 | task[i]->father = 1; | ||
110 | if (task[i]->state == TASK_ZOMBIE) | ||
111 | /* assumption task[1] is always init */ | ||
112 | (void) send_sig(SIGCHLD, task[1], 1); | ||
113 | } | ||
114 | for (i=0 ; i<NR_OPEN ; i++) | ||
115 | if (current->filp[i]) | ||
116 | sys_close(i); | ||
117 | iput(current->pwd); | ||
118 | current->pwd=NULL; | ||
119 | iput(current->root); | ||
120 | current->root=NULL; | ||
121 | iput(current->executable); | ||
122 | current->executable=NULL; | ||
123 | if (current->leader && current->tty >= 0) | ||
124 | tty_table[current->tty].pgrp = 0; | ||
125 | if (last_task_used_math == current) | ||
126 | last_task_used_math = NULL; | ||
127 | if (current->leader) | ||
128 | kill_session(); | ||
129 | current->state = TASK_ZOMBIE; | ||
130 | current->exit_code = code; | ||
131 | tell_father(current->father); | ||
132 | schedule(); | ||
133 | return (-1); /* just to suppress warnings */ | ||
134 | } | ||
135 | |||
136 | int sys_exit(int error_code) | ||
137 | { | ||
138 | return do_exit((error_code&0xff)<<8); | ||
139 | } | ||
140 | |||
141 | int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) | ||
142 | { | ||
143 | int flag, code; | ||
144 | struct task_struct ** p; | ||
145 | |||
146 | verify_area(stat_addr,4); | ||
147 | repeat: | ||
148 | flag=0; | ||
149 | for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) { | ||
150 | if (!*p || *p == current) | ||
151 | continue; | ||
152 | if ((*p)->father != current->pid) | ||
153 | continue; | ||
154 | if (pid>0) { | ||
155 | if ((*p)->pid != pid) | ||
156 | continue; | ||
157 | } else if (!pid) { | ||
158 | if ((*p)->pgrp != current->pgrp) | ||
159 | continue; | ||
160 | } else if (pid != -1) { | ||
161 | if ((*p)->pgrp != -pid) | ||
162 | continue; | ||
163 | } | ||
164 | switch ((*p)->state) { | ||
165 | case TASK_STOPPED: | ||
166 | if (!(options & WUNTRACED)) | ||
167 | continue; | ||
168 | put_fs_long(0x7f,stat_addr); | ||
169 | return (*p)->pid; | ||
170 | case TASK_ZOMBIE: | ||
171 | current->cutime += (*p)->utime; | ||
172 | current->cstime += (*p)->stime; | ||
173 | flag = (*p)->pid; | ||
174 | code = (*p)->exit_code; | ||
175 | release(*p); | ||
176 | put_fs_long(code,stat_addr); | ||
177 | return flag; | ||
178 | default: | ||
179 | flag=1; | ||
180 | continue; | ||
181 | } | ||
182 | } | ||
183 | if (flag) { | ||
184 | if (options & WNOHANG) | ||
185 | return 0; | ||
186 | current->state=TASK_INTERRUPTIBLE; | ||
187 | schedule(); | ||
188 | if (!(current->signal &= ~(1<<(SIGCHLD-1)))) | ||
189 | goto repeat; | ||
190 | else | ||
191 | return -EINTR; | ||
192 | } | ||
193 | return -ECHILD; | ||
194 | } | ||
195 | |||
196 | |||
diff --git a/src/kernel/fork.c b/src/kernel/fork.c new file mode 100644 index 0000000..018a501 --- /dev/null +++ b/src/kernel/fork.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * linux/kernel/fork.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 'fork.c' contains the help-routines for the 'fork' system call | ||
9 | * (see also system_call.s), and some misc functions ('verify_area'). | ||
10 | * Fork is rather simple, once you get the hang of it, but the memory | ||
11 | * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' | ||
12 | */ | ||
13 | #include <string.h> | ||
14 | #include <errno.h> | ||
15 | |||
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <asm/segment.h> | ||
19 | #include <asm/system.h> | ||
20 | |||
21 | extern void write_verify(unsigned long address); | ||
22 | |||
23 | long last_pid=0; | ||
24 | |||
25 | void verify_area(void * addr,int size) | ||
26 | { | ||
27 | unsigned long start; | ||
28 | |||
29 | start = (unsigned long) addr; | ||
30 | size += start & 0xfff; | ||
31 | start &= 0xfffff000; | ||
32 | start += get_base(current->ldt[2]); | ||
33 | while (size>0) { | ||
34 | size -= 4096; | ||
35 | write_verify(start); | ||
36 | start += 4096; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | int copy_mem(int nr,struct task_struct * p) | ||
41 | { | ||
42 | unsigned long old_data_base,new_data_base,data_limit; | ||
43 | unsigned long old_code_base,new_code_base,code_limit; | ||
44 | |||
45 | code_limit=get_limit(0x0f); | ||
46 | data_limit=get_limit(0x17); | ||
47 | old_code_base = get_base(current->ldt[1]); | ||
48 | old_data_base = get_base(current->ldt[2]); | ||
49 | if (old_data_base != old_code_base) | ||
50 | panic("We don't support separate I&D"); | ||
51 | if (data_limit < code_limit) | ||
52 | panic("Bad data_limit"); | ||
53 | new_data_base = new_code_base = nr * 0x4000000; | ||
54 | p->start_code = new_code_base; | ||
55 | set_base(p->ldt[1],new_code_base); | ||
56 | set_base(p->ldt[2],new_data_base); | ||
57 | if (copy_page_tables(old_data_base,new_data_base,data_limit)) { | ||
58 | printk("free_page_tables: from copy_mem\n"); | ||
59 | free_page_tables(new_data_base,data_limit); | ||
60 | return -ENOMEM; | ||
61 | } | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Ok, this is the main fork-routine. It copies the system process | ||
67 | * information (task[nr]) and sets up the necessary registers. It | ||
68 | * also copies the data segment in it's entirety. | ||
69 | */ | ||
70 | int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, | ||
71 | long ebx,long ecx,long edx, | ||
72 | long fs,long es,long ds, | ||
73 | long eip,long cs,long eflags,long esp,long ss) | ||
74 | { | ||
75 | struct task_struct *p; | ||
76 | int i; | ||
77 | struct file *f; | ||
78 | |||
79 | p = (struct task_struct *) get_free_page(); | ||
80 | if (!p) | ||
81 | return -EAGAIN; | ||
82 | task[nr] = p; | ||
83 | |||
84 | // NOTE!: the following statement now work with gcc 4.3.2 now, and you | ||
85 | // must compile _THIS_ memcpy without no -O of gcc.#ifndef GCC4_3 | ||
86 | *p = *current; /* NOTE! this doesn't copy the supervisor stack */ | ||
87 | p->state = TASK_UNINTERRUPTIBLE; | ||
88 | p->pid = last_pid; | ||
89 | p->father = current->pid; | ||
90 | p->counter = p->priority; | ||
91 | p->signal = 0; | ||
92 | p->alarm = 0; | ||
93 | p->leader = 0; /* process leadership doesn't inherit */ | ||
94 | p->utime = p->stime = 0; | ||
95 | p->cutime = p->cstime = 0; | ||
96 | p->start_time = jiffies; | ||
97 | p->tss.back_link = 0; | ||
98 | p->tss.esp0 = PAGE_SIZE + (long) p; | ||
99 | p->tss.ss0 = 0x10; | ||
100 | p->tss.eip = eip; | ||
101 | p->tss.eflags = eflags; | ||
102 | p->tss.eax = 0; | ||
103 | p->tss.ecx = ecx; | ||
104 | p->tss.edx = edx; | ||
105 | p->tss.ebx = ebx; | ||
106 | p->tss.esp = esp; | ||
107 | p->tss.ebp = ebp; | ||
108 | p->tss.esi = esi; | ||
109 | p->tss.edi = edi; | ||
110 | p->tss.es = es & 0xffff; | ||
111 | p->tss.cs = cs & 0xffff; | ||
112 | p->tss.ss = ss & 0xffff; | ||
113 | p->tss.ds = ds & 0xffff; | ||
114 | p->tss.fs = fs & 0xffff; | ||
115 | p->tss.gs = gs & 0xffff; | ||
116 | p->tss.ldt = _LDT(nr); | ||
117 | p->tss.trace_bitmap = 0x80000000; | ||
118 | if (last_task_used_math == current) | ||
119 | __asm__("clts ; fnsave %0"::"m" (p->tss.i387)); | ||
120 | if (copy_mem(nr,p)) { | ||
121 | task[nr] = NULL; | ||
122 | free_page((long) p); | ||
123 | return -EAGAIN; | ||
124 | } | ||
125 | for (i=0; i<NR_OPEN;i++) | ||
126 | if ((f=p->filp[i])) | ||
127 | f->f_count++; | ||
128 | if (current->pwd) | ||
129 | current->pwd->i_count++; | ||
130 | if (current->root) | ||
131 | current->root->i_count++; | ||
132 | if (current->executable) | ||
133 | current->executable->i_count++; | ||
134 | set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); | ||
135 | set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); | ||
136 | p->state = TASK_RUNNING; /* do this last, just in case */ | ||
137 | return last_pid; | ||
138 | } | ||
139 | |||
140 | int find_empty_process(void) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | repeat: | ||
145 | if ((++last_pid)<0) last_pid=1; | ||
146 | for(i=0 ; i<NR_TASKS ; i++) | ||
147 | if (task[i] && task[i]->pid == last_pid) goto repeat; | ||
148 | for(i=1 ; i<NR_TASKS ; i++) | ||
149 | if (!task[i]) | ||
150 | return i; | ||
151 | return -EAGAIN; | ||
152 | } | ||
diff --git a/src/kernel/math/Makefile b/src/kernel/math/Makefile new file mode 100644 index 0000000..b79ddd7 --- /dev/null +++ b/src/kernel/math/Makefile | |||
@@ -0,0 +1,39 @@ | |||
1 | # | ||
2 | # Makefile for the FREAX-kernel character device drivers. | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | include ../../Makefile.header | ||
10 | |||
11 | CFLAGS += -I../../include | ||
12 | CPP += -I../../include | ||
13 | |||
14 | .c.s: | ||
15 | @$(CC) $(CFLAGS) \ | ||
16 | -S -o $*.s $< | ||
17 | .s.o: | ||
18 | @$(AS) -o $*.o $< | ||
19 | .c.o: | ||
20 | @$(CC) $(CFLAGS) \ | ||
21 | -c -o $*.o $< | ||
22 | |||
23 | OBJS = math_emulate.o | ||
24 | |||
25 | math.a: $(OBJS) | ||
26 | @$(AR) rcs math.a $(OBJS) | ||
27 | @sync | ||
28 | |||
29 | clean: | ||
30 | @rm -f core *.o *.a tmp_make | ||
31 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
32 | |||
33 | dep: | ||
34 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
35 | @(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ | ||
36 | $(CPP) -M $$i;done) >> tmp_make | ||
37 | @cp tmp_make Makefile | ||
38 | |||
39 | ### Dependencies: | ||
diff --git a/src/kernel/math/math_emulate.c b/src/kernel/math/math_emulate.c new file mode 100644 index 0000000..825e528 --- /dev/null +++ b/src/kernel/math/math_emulate.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * linux/kernel/math/math_emulate.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This directory should contain the math-emulation code. | ||
9 | * Currently only results in a signal. | ||
10 | */ | ||
11 | |||
12 | #include <signal.h> | ||
13 | |||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <asm/segment.h> | ||
17 | |||
18 | void math_emulate(long edi, long esi, long ebp, long sys_call_ret, | ||
19 | long eax,long ebx,long ecx,long edx, | ||
20 | unsigned short fs,unsigned short es,unsigned short ds, | ||
21 | unsigned long eip,unsigned short cs,unsigned long eflags, | ||
22 | unsigned short ss, unsigned long esp) | ||
23 | { | ||
24 | unsigned char first, second; | ||
25 | |||
26 | /* 0x0007 means user code space */ | ||
27 | if (cs != 0x000F) { | ||
28 | printk("math_emulate: %04x:%08x\n\r",cs,eip); | ||
29 | panic("Math emulation needed in kernel"); | ||
30 | } | ||
31 | first = get_fs_byte((char *)((*&eip)++)); | ||
32 | second = get_fs_byte((char *)((*&eip)++)); | ||
33 | printk("%04x:%08x %02x %02x\n\r",cs,eip-2,first,second); | ||
34 | current->signal |= 1<<(SIGFPE-1); | ||
35 | } | ||
36 | |||
37 | void math_error(void) | ||
38 | { | ||
39 | __asm__("fnclex"); | ||
40 | if (last_task_used_math) | ||
41 | last_task_used_math->signal |= 1<<(SIGFPE-1); | ||
42 | } | ||
diff --git a/src/kernel/mktime.c b/src/kernel/mktime.c new file mode 100644 index 0000000..d125ded --- /dev/null +++ b/src/kernel/mktime.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * linux/kernel/mktime.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <time.h> | ||
8 | |||
9 | /* | ||
10 | * This isn't the library routine, it is only used in the kernel. | ||
11 | * as such, we don't care about years<1970 etc, but assume everything | ||
12 | * is ok. Similarly, TZ etc is happily ignored. We just do everything | ||
13 | * as easily as possible. Let's find something public for the library | ||
14 | * routines (although I think minix times is public). | ||
15 | */ | ||
16 | /* | ||
17 | * PS. I hate whoever though up the year 1970 - couldn't they have gotten | ||
18 | * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. | ||
19 | */ | ||
20 | #define MINUTE 60 | ||
21 | #define HOUR (60*MINUTE) | ||
22 | #define DAY (24*HOUR) | ||
23 | #define YEAR (365*DAY) | ||
24 | |||
25 | /* interestingly, we assume leap-years */ | ||
26 | static int month[12] = { | ||
27 | 0, | ||
28 | DAY*(31), | ||
29 | DAY*(31+29), | ||
30 | DAY*(31+29+31), | ||
31 | DAY*(31+29+31+30), | ||
32 | DAY*(31+29+31+30+31), | ||
33 | DAY*(31+29+31+30+31+30), | ||
34 | DAY*(31+29+31+30+31+30+31), | ||
35 | DAY*(31+29+31+30+31+30+31+31), | ||
36 | DAY*(31+29+31+30+31+30+31+31+30), | ||
37 | DAY*(31+29+31+30+31+30+31+31+30+31), | ||
38 | DAY*(31+29+31+30+31+30+31+31+30+31+30) | ||
39 | }; | ||
40 | |||
41 | long kernel_mktime(struct tm * tm) | ||
42 | { | ||
43 | long res; | ||
44 | int year; | ||
45 | if (tm->tm_year >= 70) | ||
46 | year = tm->tm_year - 70; | ||
47 | else | ||
48 | year = tm->tm_year + 100 -70; /* Y2K bug fix by hellotigercn 20110803 */ | ||
49 | /* magic offsets (y+1) needed to get leapyears right.*/ | ||
50 | res = YEAR*year + DAY*((year+1)/4); | ||
51 | res += month[tm->tm_mon]; | ||
52 | /* and (y+2) here. If it wasn't a leap-year, we have to adjust */ | ||
53 | if (tm->tm_mon>1 && ((year+2)%4)) | ||
54 | res -= DAY; | ||
55 | res += DAY*(tm->tm_mday-1); | ||
56 | res += HOUR*tm->tm_hour; | ||
57 | res += MINUTE*tm->tm_min; | ||
58 | res += tm->tm_sec; | ||
59 | return res; | ||
60 | } | ||
diff --git a/src/kernel/panic.c b/src/kernel/panic.c new file mode 100644 index 0000000..9a40e45 --- /dev/null +++ b/src/kernel/panic.c | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * linux/kernel/panic.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This function is used through-out the kernel (includeinh mm and fs) | ||
9 | * to indicate a major problem. | ||
10 | */ | ||
11 | #define PANIC | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | |||
16 | void sys_sync(void); /* it's really int */ | ||
17 | |||
18 | void panic(const char * s) | ||
19 | { | ||
20 | printk("Kernel panic: %s\n\r",s); | ||
21 | if (current == task[0]) | ||
22 | printk("In swapper task - not syncing\n\r"); | ||
23 | else | ||
24 | sys_sync(); | ||
25 | for(;;); | ||
26 | } | ||
diff --git a/src/kernel/printk.c b/src/kernel/printk.c new file mode 100644 index 0000000..0daa097 --- /dev/null +++ b/src/kernel/printk.c | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * linux/kernel/printk.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * When in kernel-mode, we cannot use printf, as fs is liable to | ||
9 | * point to 'interesting' things. Make a printf with fs-saving, and | ||
10 | * all is well. | ||
11 | */ | ||
12 | #include <stdarg.h> | ||
13 | #include <stddef.h> | ||
14 | |||
15 | #include <linux/kernel.h> | ||
16 | |||
17 | static char buf[1024]; | ||
18 | |||
19 | extern int vsprintf(char * buf, const char * fmt, va_list args); | ||
20 | |||
21 | int printk(const char *fmt, ...) | ||
22 | { | ||
23 | va_list args; | ||
24 | int i; | ||
25 | |||
26 | va_start(args, fmt); | ||
27 | i=vsprintf(buf,fmt,args); | ||
28 | va_end(args); | ||
29 | __asm__("push %%fs\n\t" | ||
30 | "push %%ds\n\t" | ||
31 | "pop %%fs\n\t" | ||
32 | "pushl %0\n\t" | ||
33 | "pushl $buf\n\t" | ||
34 | "pushl $0\n\t" | ||
35 | "call tty_write\n\t" | ||
36 | "addl $8,%%esp\n\t" | ||
37 | "popl %0\n\t" | ||
38 | "pop %%fs" | ||
39 | ::"r" (i):"ax","cx","dx"); | ||
40 | return i; | ||
41 | } | ||
diff --git a/src/kernel/sched.c b/src/kernel/sched.c new file mode 100644 index 0000000..15d839b --- /dev/null +++ b/src/kernel/sched.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * linux/kernel/sched.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 'sched.c' is the main kernel file. It contains scheduling primitives | ||
9 | * (sleep_on, wakeup, schedule etc) as well as a number of simple system | ||
10 | * call functions (type getpid(), which just extracts a field from | ||
11 | * current-task | ||
12 | */ | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/sys.h> | ||
16 | #include <linux/fdreg.h> | ||
17 | #include <asm/system.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/segment.h> | ||
20 | |||
21 | #include <signal.h> | ||
22 | |||
23 | #define _S(nr) (1<<((nr)-1)) | ||
24 | #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) | ||
25 | |||
26 | void show_task(int nr,struct task_struct * p) | ||
27 | { | ||
28 | int i,j = 4096-sizeof(struct task_struct); | ||
29 | |||
30 | printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); | ||
31 | i=0; | ||
32 | while (i<j && !((char *)(p+1))[i]) | ||
33 | i++; | ||
34 | printk("%d (of %d) chars free in kernel stack\n\r",i,j); | ||
35 | } | ||
36 | |||
37 | void show_stat(void) | ||
38 | { | ||
39 | int i; | ||
40 | |||
41 | for (i=0;i<NR_TASKS;i++) | ||
42 | if (task[i]) | ||
43 | show_task(i,task[i]); | ||
44 | } | ||
45 | |||
46 | #define LATCH (1193180/HZ) | ||
47 | |||
48 | extern void mem_use(void); | ||
49 | |||
50 | extern int timer_interrupt(void); | ||
51 | extern int system_call(void); | ||
52 | |||
53 | union task_union { | ||
54 | struct task_struct task; | ||
55 | char stack[PAGE_SIZE]; | ||
56 | }; | ||
57 | |||
58 | static union task_union init_task = {INIT_TASK,}; | ||
59 | |||
60 | long volatile jiffies=0; | ||
61 | long startup_time=0; | ||
62 | struct task_struct *current = &(init_task.task); | ||
63 | struct task_struct *last_task_used_math = NULL; | ||
64 | |||
65 | struct task_struct * task[NR_TASKS] = {&(init_task.task), }; | ||
66 | |||
67 | long user_stack [ PAGE_SIZE>>2 ] ; | ||
68 | |||
69 | struct { | ||
70 | long * a; | ||
71 | short b; | ||
72 | } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 }; | ||
73 | /* | ||
74 | * 'math_state_restore()' saves the current math information in the | ||
75 | * old math state array, and gets the new ones from the current task | ||
76 | */ | ||
77 | void math_state_restore() | ||
78 | { | ||
79 | if (last_task_used_math == current) | ||
80 | return; | ||
81 | __asm__("fwait"); | ||
82 | if (last_task_used_math) { | ||
83 | __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387)); | ||
84 | } | ||
85 | last_task_used_math=current; | ||
86 | if (current->used_math) { | ||
87 | __asm__("frstor %0"::"m" (current->tss.i387)); | ||
88 | } else { | ||
89 | __asm__("fninit"::); | ||
90 | current->used_math=1; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * 'schedule()' is the scheduler function. This is GOOD CODE! There | ||
96 | * probably won't be any reason to change this, as it should work well | ||
97 | * in all circumstances (ie gives IO-bound processes good response etc). | ||
98 | * The one thing you might take a look at is the signal-handler code here. | ||
99 | * | ||
100 | * NOTE!! Task 0 is the 'idle' task, which gets called when no other | ||
101 | * tasks can run. It can not be killed, and it cannot sleep. The 'state' | ||
102 | * information in task[0] is never used. | ||
103 | */ | ||
104 | void schedule(void) | ||
105 | { | ||
106 | int i,next,c; | ||
107 | struct task_struct ** p; | ||
108 | |||
109 | /* check alarm, wake up any interruptible tasks that have got a signal */ | ||
110 | |||
111 | for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) | ||
112 | if (*p) { | ||
113 | if ((*p)->alarm && (*p)->alarm < jiffies) { | ||
114 | (*p)->signal |= (1<<(SIGALRM-1)); | ||
115 | (*p)->alarm = 0; | ||
116 | } | ||
117 | if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) && | ||
118 | (*p)->state==TASK_INTERRUPTIBLE) | ||
119 | (*p)->state=TASK_RUNNING; | ||
120 | } | ||
121 | |||
122 | /* this is the scheduler proper: */ | ||
123 | |||
124 | while (1) { | ||
125 | c = -1; | ||
126 | next = 0; | ||
127 | i = NR_TASKS; | ||
128 | p = &task[NR_TASKS]; | ||
129 | while (--i) { | ||
130 | if (!*--p) | ||
131 | continue; | ||
132 | if ((*p)->state == TASK_RUNNING && (*p)->counter > c) | ||
133 | c = (*p)->counter, next = i; | ||
134 | } | ||
135 | if (c) break; | ||
136 | for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) | ||
137 | if (*p) | ||
138 | (*p)->counter = ((*p)->counter >> 1) + | ||
139 | (*p)->priority; | ||
140 | } | ||
141 | switch_to(next); | ||
142 | } | ||
143 | |||
144 | int sys_pause(void) | ||
145 | { | ||
146 | current->state = TASK_INTERRUPTIBLE; | ||
147 | schedule(); | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | void sleep_on(struct task_struct **p) | ||
152 | { | ||
153 | struct task_struct *tmp; | ||
154 | |||
155 | if (!p) | ||
156 | return; | ||
157 | if (current == &(init_task.task)) | ||
158 | panic("task[0] trying to sleep"); | ||
159 | tmp = *p; | ||
160 | *p = current; | ||
161 | current->state = TASK_UNINTERRUPTIBLE; | ||
162 | schedule(); | ||
163 | if (tmp) | ||
164 | tmp->state=0; | ||
165 | } | ||
166 | |||
167 | void interruptible_sleep_on(struct task_struct **p) | ||
168 | { | ||
169 | struct task_struct *tmp; | ||
170 | |||
171 | if (!p) | ||
172 | return; | ||
173 | if (current == &(init_task.task)) | ||
174 | panic("task[0] trying to sleep"); | ||
175 | tmp=*p; | ||
176 | *p=current; | ||
177 | repeat: current->state = TASK_INTERRUPTIBLE; | ||
178 | schedule(); | ||
179 | if (*p && *p != current) { | ||
180 | (**p).state=0; | ||
181 | goto repeat; | ||
182 | } | ||
183 | *p=NULL; | ||
184 | if (tmp) | ||
185 | tmp->state=0; | ||
186 | } | ||
187 | |||
188 | void wake_up(struct task_struct **p) | ||
189 | { | ||
190 | if (p && *p) { | ||
191 | (**p).state=0; | ||
192 | *p=NULL; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * OK, here are some floppy things that shouldn't be in the kernel | ||
198 | * proper. They are here because the floppy needs a timer, and this | ||
199 | * was the easiest way of doing it. | ||
200 | */ | ||
201 | static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL}; | ||
202 | static int mon_timer[4]={0,0,0,0}; | ||
203 | static int moff_timer[4]={0,0,0,0}; | ||
204 | unsigned char current_DOR = 0x0C; | ||
205 | |||
206 | int ticks_to_floppy_on(unsigned int nr) | ||
207 | { | ||
208 | extern unsigned char selected; | ||
209 | unsigned char mask = 0x10 << nr; | ||
210 | |||
211 | if (nr>3) | ||
212 | panic("floppy_on: nr>3"); | ||
213 | moff_timer[nr]=10000; /* 100 s = very big :-) */ | ||
214 | cli(); /* use floppy_off to turn it off */ | ||
215 | mask |= current_DOR; | ||
216 | if (!selected) { | ||
217 | mask &= 0xFC; | ||
218 | mask |= nr; | ||
219 | } | ||
220 | if (mask != current_DOR) { | ||
221 | outb(mask,FD_DOR); | ||
222 | if ((mask ^ current_DOR) & 0xf0) | ||
223 | mon_timer[nr] = HZ/2; | ||
224 | else if (mon_timer[nr] < 2) | ||
225 | mon_timer[nr] = 2; | ||
226 | current_DOR = mask; | ||
227 | } | ||
228 | sti(); | ||
229 | return mon_timer[nr]; | ||
230 | } | ||
231 | |||
232 | void floppy_on(unsigned int nr) | ||
233 | { | ||
234 | cli(); | ||
235 | while (ticks_to_floppy_on(nr)) | ||
236 | sleep_on(nr+wait_motor); | ||
237 | sti(); | ||
238 | } | ||
239 | |||
240 | void floppy_off(unsigned int nr) | ||
241 | { | ||
242 | moff_timer[nr]=3*HZ; | ||
243 | } | ||
244 | |||
245 | void do_floppy_timer(void) | ||
246 | { | ||
247 | int i; | ||
248 | unsigned char mask = 0x10; | ||
249 | |||
250 | for (i=0 ; i<4 ; i++,mask <<= 1) { | ||
251 | if (!(mask & current_DOR)) | ||
252 | continue; | ||
253 | if (mon_timer[i]) { | ||
254 | if (!--mon_timer[i]) | ||
255 | wake_up(i+wait_motor); | ||
256 | } else if (!moff_timer[i]) { | ||
257 | current_DOR &= ~mask; | ||
258 | outb(current_DOR,FD_DOR); | ||
259 | } else | ||
260 | moff_timer[i]--; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | #define TIME_REQUESTS 64 | ||
265 | |||
266 | static struct timer_list { | ||
267 | long jiffies; | ||
268 | void (*fn)(); | ||
269 | struct timer_list * next; | ||
270 | } timer_list[TIME_REQUESTS], * next_timer = NULL; | ||
271 | |||
272 | void add_timer(long jiffies, void (*fn)(void)) | ||
273 | { | ||
274 | struct timer_list * p; | ||
275 | |||
276 | if (!fn) | ||
277 | return; | ||
278 | cli(); | ||
279 | if (jiffies <= 0) | ||
280 | (fn)(); | ||
281 | else { | ||
282 | for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++) | ||
283 | if (!p->fn) | ||
284 | break; | ||
285 | if (p >= timer_list + TIME_REQUESTS) | ||
286 | panic("No more time requests free"); | ||
287 | p->fn = fn; | ||
288 | p->jiffies = jiffies; | ||
289 | p->next = next_timer; | ||
290 | next_timer = p; | ||
291 | while (p->next && p->next->jiffies < p->jiffies) { | ||
292 | p->jiffies -= p->next->jiffies; | ||
293 | fn = p->fn; | ||
294 | p->fn = p->next->fn; | ||
295 | p->next->fn = fn; | ||
296 | jiffies = p->jiffies; | ||
297 | p->jiffies = p->next->jiffies; | ||
298 | p->next->jiffies = jiffies; | ||
299 | p = p->next; | ||
300 | } | ||
301 | } | ||
302 | sti(); | ||
303 | } | ||
304 | |||
305 | void do_timer(long cpl) | ||
306 | { | ||
307 | extern int beepcount; | ||
308 | extern void sysbeepstop(void); | ||
309 | |||
310 | if (beepcount) | ||
311 | if (!--beepcount) | ||
312 | sysbeepstop(); | ||
313 | |||
314 | if (cpl) | ||
315 | current->utime++; | ||
316 | else | ||
317 | current->stime++; | ||
318 | |||
319 | if (next_timer) { | ||
320 | next_timer->jiffies--; | ||
321 | while (next_timer && next_timer->jiffies <= 0) { | ||
322 | void (*fn)(void); | ||
323 | |||
324 | fn = next_timer->fn; | ||
325 | next_timer->fn = NULL; | ||
326 | next_timer = next_timer->next; | ||
327 | (fn)(); | ||
328 | } | ||
329 | } | ||
330 | if (current_DOR & 0xf0) | ||
331 | do_floppy_timer(); | ||
332 | if ((--current->counter)>0) return; | ||
333 | current->counter=0; | ||
334 | if (!cpl) return; | ||
335 | schedule(); | ||
336 | } | ||
337 | |||
338 | int sys_alarm(long seconds) | ||
339 | { | ||
340 | int old = current->alarm; | ||
341 | |||
342 | if (old) | ||
343 | old = (old - jiffies) / HZ; | ||
344 | current->alarm = (seconds>0)?(jiffies+HZ*seconds):0; | ||
345 | return (old); | ||
346 | } | ||
347 | |||
348 | int sys_getpid(void) | ||
349 | { | ||
350 | return current->pid; | ||
351 | } | ||
352 | |||
353 | int sys_getppid(void) | ||
354 | { | ||
355 | return current->father; | ||
356 | } | ||
357 | |||
358 | int sys_getuid(void) | ||
359 | { | ||
360 | return current->uid; | ||
361 | } | ||
362 | |||
363 | int sys_geteuid(void) | ||
364 | { | ||
365 | return current->euid; | ||
366 | } | ||
367 | |||
368 | int sys_getgid(void) | ||
369 | { | ||
370 | return current->gid; | ||
371 | } | ||
372 | |||
373 | int sys_getegid(void) | ||
374 | { | ||
375 | return current->egid; | ||
376 | } | ||
377 | |||
378 | int sys_nice(long increment) | ||
379 | { | ||
380 | if (current->priority-increment>0) | ||
381 | current->priority -= increment; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | void sched_init(void) | ||
386 | { | ||
387 | int i; | ||
388 | struct desc_struct * p; | ||
389 | |||
390 | if (sizeof(struct sigaction) != 16) | ||
391 | panic("Struct sigaction MUST be 16 bytes"); | ||
392 | set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); | ||
393 | set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); | ||
394 | p = gdt+2+FIRST_TSS_ENTRY; | ||
395 | for(i=1;i<NR_TASKS;i++) { | ||
396 | task[i] = NULL; | ||
397 | p->a=p->b=0; | ||
398 | p++; | ||
399 | p->a=p->b=0; | ||
400 | p++; | ||
401 | } | ||
402 | /* Clear NT, so that we won't have troubles with that later on */ | ||
403 | __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); | ||
404 | ltr(0); | ||
405 | lldt(0); | ||
406 | outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */ | ||
407 | outb_p(LATCH & 0xff , 0x40); /* LSB */ | ||
408 | outb(LATCH >> 8 , 0x40); /* MSB */ | ||
409 | set_intr_gate(0x20,&timer_interrupt); | ||
410 | outb(inb_p(0x21)&~0x01,0x21); | ||
411 | set_system_gate(0x80,&system_call); | ||
412 | } | ||
diff --git a/src/kernel/signal.c b/src/kernel/signal.c new file mode 100644 index 0000000..c6afb3a --- /dev/null +++ b/src/kernel/signal.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * linux/kernel/signal.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <linux/sched.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <asm/segment.h> | ||
10 | |||
11 | #include <signal.h> | ||
12 | |||
13 | void do_exit(int error_code); | ||
14 | |||
15 | int sys_sgetmask() | ||
16 | { | ||
17 | return current->blocked; | ||
18 | } | ||
19 | |||
20 | int sys_ssetmask(int newmask) | ||
21 | { | ||
22 | int old=current->blocked; | ||
23 | |||
24 | current->blocked = newmask & ~(1<<(SIGKILL-1)); | ||
25 | return old; | ||
26 | } | ||
27 | |||
28 | static inline void save_old(char * from,char * to) | ||
29 | { | ||
30 | int i; | ||
31 | |||
32 | verify_area(to, sizeof(struct sigaction)); | ||
33 | for (i=0 ; i< sizeof(struct sigaction) ; i++) { | ||
34 | put_fs_byte(*from,to); | ||
35 | from++; | ||
36 | to++; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | static inline void get_new(char * from,char * to) | ||
41 | { | ||
42 | int i; | ||
43 | |||
44 | for (i=0 ; i< sizeof(struct sigaction) ; i++) | ||
45 | *(to++) = get_fs_byte(from++); | ||
46 | } | ||
47 | |||
48 | int sys_signal(int signum, long handler, long restorer) | ||
49 | { | ||
50 | struct sigaction tmp; | ||
51 | |||
52 | if (signum<1 || signum>32 || signum==SIGKILL) | ||
53 | return -1; | ||
54 | tmp.sa_handler = (void (*)(int)) handler; | ||
55 | tmp.sa_mask = 0; | ||
56 | tmp.sa_flags = SA_ONESHOT | SA_NOMASK; | ||
57 | tmp.sa_restorer = (void (*)(void)) restorer; | ||
58 | handler = (long) current->sigaction[signum-1].sa_handler; | ||
59 | current->sigaction[signum-1] = tmp; | ||
60 | return handler; | ||
61 | } | ||
62 | |||
63 | int sys_sigaction(int signum, const struct sigaction * action, | ||
64 | struct sigaction * oldaction) | ||
65 | { | ||
66 | struct sigaction tmp; | ||
67 | |||
68 | if (signum<1 || signum>32 || signum==SIGKILL) | ||
69 | return -1; | ||
70 | tmp = current->sigaction[signum-1]; | ||
71 | get_new((char *) action, | ||
72 | (char *) (signum-1+current->sigaction)); | ||
73 | if (oldaction) | ||
74 | save_old((char *) &tmp,(char *) oldaction); | ||
75 | if (current->sigaction[signum-1].sa_flags & SA_NOMASK) | ||
76 | current->sigaction[signum-1].sa_mask = 0; | ||
77 | else | ||
78 | current->sigaction[signum-1].sa_mask |= (1<<(signum-1)); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | void do_signal(long signr,long eax, long ebx, long ecx, long edx, | ||
83 | long fs, long es, long ds, | ||
84 | long eip, long cs, long eflags, | ||
85 | unsigned long * esp, long ss) | ||
86 | { | ||
87 | unsigned long sa_handler; | ||
88 | long old_eip=eip; | ||
89 | struct sigaction * sa = current->sigaction + signr - 1; | ||
90 | int longs; | ||
91 | unsigned long * tmp_esp; | ||
92 | |||
93 | sa_handler = (unsigned long) sa->sa_handler; | ||
94 | if (sa_handler==1) | ||
95 | return; | ||
96 | if (!sa_handler) { | ||
97 | if (signr==SIGCHLD) | ||
98 | return; | ||
99 | else | ||
100 | do_exit(1<<(signr-1)); | ||
101 | } | ||
102 | if (sa->sa_flags & SA_ONESHOT) | ||
103 | sa->sa_handler = NULL; | ||
104 | *(&eip) = sa_handler; | ||
105 | longs = (sa->sa_flags & SA_NOMASK)?7:8; | ||
106 | *(&esp) -= longs; | ||
107 | verify_area(esp,longs*4); | ||
108 | tmp_esp=esp; | ||
109 | put_fs_long((long) sa->sa_restorer,tmp_esp++); | ||
110 | put_fs_long(signr,tmp_esp++); | ||
111 | if (!(sa->sa_flags & SA_NOMASK)) | ||
112 | put_fs_long(current->blocked,tmp_esp++); | ||
113 | put_fs_long(eax,tmp_esp++); | ||
114 | put_fs_long(ecx,tmp_esp++); | ||
115 | put_fs_long(edx,tmp_esp++); | ||
116 | put_fs_long(eflags,tmp_esp++); | ||
117 | put_fs_long(old_eip,tmp_esp++); | ||
118 | current->blocked |= sa->sa_mask; | ||
119 | } | ||
diff --git a/src/kernel/sys.c b/src/kernel/sys.c new file mode 100644 index 0000000..2c01e67 --- /dev/null +++ b/src/kernel/sys.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * linux/kernel/sys.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <errno.h> | ||
8 | |||
9 | #include <linux/sched.h> | ||
10 | #include <linux/tty.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <asm/segment.h> | ||
13 | #include <sys/times.h> | ||
14 | #include <sys/utsname.h> | ||
15 | |||
16 | int sys_ftime() | ||
17 | { | ||
18 | return -ENOSYS; | ||
19 | } | ||
20 | |||
21 | int sys_break() | ||
22 | { | ||
23 | return -ENOSYS; | ||
24 | } | ||
25 | |||
26 | int sys_ptrace() | ||
27 | { | ||
28 | return -ENOSYS; | ||
29 | } | ||
30 | |||
31 | int sys_stty() | ||
32 | { | ||
33 | return -ENOSYS; | ||
34 | } | ||
35 | |||
36 | int sys_gtty() | ||
37 | { | ||
38 | return -ENOSYS; | ||
39 | } | ||
40 | |||
41 | int sys_rename() | ||
42 | { | ||
43 | return -ENOSYS; | ||
44 | } | ||
45 | |||
46 | int sys_prof() | ||
47 | { | ||
48 | return -ENOSYS; | ||
49 | } | ||
50 | |||
51 | int sys_setregid(int rgid, int egid) | ||
52 | { | ||
53 | if (rgid>0) { | ||
54 | if ((current->gid == rgid) || | ||
55 | suser()) | ||
56 | current->gid = rgid; | ||
57 | else | ||
58 | return(-EPERM); | ||
59 | } | ||
60 | if (egid>0) { | ||
61 | if ((current->gid == egid) || | ||
62 | (current->egid == egid) || | ||
63 | (current->sgid == egid) || | ||
64 | suser()) | ||
65 | current->egid = egid; | ||
66 | else | ||
67 | return(-EPERM); | ||
68 | } | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | int sys_setgid(int gid) | ||
73 | { | ||
74 | return(sys_setregid(gid, gid)); | ||
75 | } | ||
76 | |||
77 | int sys_acct() | ||
78 | { | ||
79 | return -ENOSYS; | ||
80 | } | ||
81 | |||
82 | int sys_phys() | ||
83 | { | ||
84 | return -ENOSYS; | ||
85 | } | ||
86 | |||
87 | int sys_lock() | ||
88 | { | ||
89 | return -ENOSYS; | ||
90 | } | ||
91 | |||
92 | int sys_mpx() | ||
93 | { | ||
94 | return -ENOSYS; | ||
95 | } | ||
96 | |||
97 | int sys_ulimit() | ||
98 | { | ||
99 | return -ENOSYS; | ||
100 | } | ||
101 | |||
102 | int sys_time(long * tloc) | ||
103 | { | ||
104 | int i; | ||
105 | |||
106 | i = CURRENT_TIME; | ||
107 | if (tloc) { | ||
108 | verify_area(tloc,4); | ||
109 | put_fs_long(i,(unsigned long *)tloc); | ||
110 | } | ||
111 | return i; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Unprivileged users may change the real user id to the effective uid | ||
116 | * or vice versa. | ||
117 | */ | ||
118 | int sys_setreuid(int ruid, int euid) | ||
119 | { | ||
120 | int old_ruid = current->uid; | ||
121 | |||
122 | if (ruid>0) { | ||
123 | if ((current->euid==ruid) || | ||
124 | (old_ruid == ruid) || | ||
125 | suser()) | ||
126 | current->uid = ruid; | ||
127 | else | ||
128 | return(-EPERM); | ||
129 | } | ||
130 | if (euid>0) { | ||
131 | if ((old_ruid == euid) || | ||
132 | (current->euid == euid) || | ||
133 | suser()) | ||
134 | current->euid = euid; | ||
135 | else { | ||
136 | current->uid = old_ruid; | ||
137 | return(-EPERM); | ||
138 | } | ||
139 | } | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | int sys_setuid(int uid) | ||
144 | { | ||
145 | return(sys_setreuid(uid, uid)); | ||
146 | } | ||
147 | |||
148 | int sys_stime(long * tptr) | ||
149 | { | ||
150 | if (!suser()) | ||
151 | return -EPERM; | ||
152 | startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ; | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | int sys_times(struct tms * tbuf) | ||
157 | { | ||
158 | if (tbuf) { | ||
159 | verify_area(tbuf,sizeof *tbuf); | ||
160 | put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); | ||
161 | put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); | ||
162 | put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); | ||
163 | put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); | ||
164 | } | ||
165 | return jiffies; | ||
166 | } | ||
167 | |||
168 | int sys_brk(unsigned long end_data_seg) | ||
169 | { | ||
170 | if (end_data_seg >= current->end_code && | ||
171 | end_data_seg < current->start_stack - 16384) | ||
172 | current->brk = end_data_seg; | ||
173 | return current->brk; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * This needs some heave checking ... | ||
178 | * I just haven't get the stomach for it. I also don't fully | ||
179 | * understand sessions/pgrp etc. Let somebody who does explain it. | ||
180 | */ | ||
181 | int sys_setpgid(int pid, int pgid) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | if (!pid) | ||
186 | pid = current->pid; | ||
187 | if (!pgid) | ||
188 | pgid = current->pid; | ||
189 | for (i=0 ; i<NR_TASKS ; i++) | ||
190 | if (task[i] && task[i]->pid==pid) { | ||
191 | if (task[i]->leader) | ||
192 | return -EPERM; | ||
193 | if (task[i]->session != current->session) | ||
194 | return -EPERM; | ||
195 | task[i]->pgrp = pgid; | ||
196 | return 0; | ||
197 | } | ||
198 | return -ESRCH; | ||
199 | } | ||
200 | |||
201 | int sys_getpgrp(void) | ||
202 | { | ||
203 | return current->pgrp; | ||
204 | } | ||
205 | |||
206 | int sys_setsid(void) | ||
207 | { | ||
208 | if (current->leader && !suser()) | ||
209 | return -EPERM; | ||
210 | current->leader = 1; | ||
211 | current->session = current->pgrp = current->pid; | ||
212 | current->tty = -1; | ||
213 | return current->pgrp; | ||
214 | } | ||
215 | |||
216 | int sys_uname(struct utsname * name) | ||
217 | { | ||
218 | static struct utsname thisname = { | ||
219 | "linux .0","nodename","release ","version ","machine " | ||
220 | }; | ||
221 | int i; | ||
222 | |||
223 | if (!name) return -ERROR; | ||
224 | verify_area(name,sizeof *name); | ||
225 | for(i=0;i<sizeof *name;i++) | ||
226 | put_fs_byte(((char *) &thisname)[i],i+(char *) name); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | int sys_umask(int mask) | ||
231 | { | ||
232 | int old = current->umask; | ||
233 | |||
234 | current->umask = mask & 0777; | ||
235 | return (old); | ||
236 | } | ||
diff --git a/src/kernel/system_call.s b/src/kernel/system_call.s new file mode 100644 index 0000000..c602cd8 --- /dev/null +++ b/src/kernel/system_call.s | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * linux/kernel/system_call.s | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * system_call.s contains the system-call low-level handling routines. | ||
9 | * This also contains the timer-interrupt handler, as some of the code is | ||
10 | * the same. The hd- and flopppy-interrupts are also here. | ||
11 | * | ||
12 | * NOTE: This code handles signal-recognition, which happens every time | ||
13 | * after a timer-interrupt and after each system call. Ordinary interrupts | ||
14 | * don't handle signal-recognition, as that would clutter them up totally | ||
15 | * unnecessarily. | ||
16 | * | ||
17 | * Stack layout in 'ret_from_system_call': | ||
18 | * | ||
19 | * 0(%esp) - %eax | ||
20 | * 4(%esp) - %ebx | ||
21 | * 8(%esp) - %ecx | ||
22 | * C(%esp) - %edx | ||
23 | * 10(%esp) - %fs | ||
24 | * 14(%esp) - %es | ||
25 | * 18(%esp) - %ds | ||
26 | * 1C(%esp) - %eip | ||
27 | * 20(%esp) - %cs | ||
28 | * 24(%esp) - %eflags | ||
29 | * 28(%esp) - %oldesp | ||
30 | * 2C(%esp) - %oldss | ||
31 | */ | ||
32 | |||
33 | SIG_CHLD = 17 | ||
34 | |||
35 | EAX = 0x00 | ||
36 | EBX = 0x04 | ||
37 | ECX = 0x08 | ||
38 | EDX = 0x0C | ||
39 | FS = 0x10 | ||
40 | ES = 0x14 | ||
41 | DS = 0x18 | ||
42 | EIP = 0x1C | ||
43 | CS = 0x20 | ||
44 | EFLAGS = 0x24 | ||
45 | OLDESP = 0x28 | ||
46 | OLDSS = 0x2C | ||
47 | |||
48 | state = 0 # these are offsets into the task-struct. | ||
49 | counter = 4 | ||
50 | priority = 8 | ||
51 | signal = 12 | ||
52 | sigaction = 16 # MUST be 16 (=len of sigaction) | ||
53 | blocked = (33*16) | ||
54 | |||
55 | # offsets within sigaction | ||
56 | sa_handler = 0 | ||
57 | sa_mask = 4 | ||
58 | sa_flags = 8 | ||
59 | sa_restorer = 12 | ||
60 | |||
61 | nr_system_calls = 72 | ||
62 | |||
63 | /* | ||
64 | * Ok, I get parallel printer interrupts while using the floppy for some | ||
65 | * strange reason. Urgel. Now I just ignore them. | ||
66 | */ | ||
67 | .globl system_call,sys_fork,timer_interrupt,sys_execve | ||
68 | .globl hd_interrupt,floppy_interrupt,parallel_interrupt | ||
69 | .globl device_not_available, coprocessor_error | ||
70 | |||
71 | .align 2 | ||
72 | bad_sys_call: | ||
73 | movl $-1,%eax | ||
74 | iret | ||
75 | .align 2 | ||
76 | reschedule: | ||
77 | pushl $ret_from_sys_call | ||
78 | jmp schedule | ||
79 | .align 2 | ||
80 | system_call: | ||
81 | cmpl $nr_system_calls-1,%eax | ||
82 | ja bad_sys_call | ||
83 | push %ds | ||
84 | push %es | ||
85 | push %fs | ||
86 | pushl %edx | ||
87 | pushl %ecx # push %ebx,%ecx,%edx as parameters | ||
88 | pushl %ebx # to the system call | ||
89 | movl $0x10,%edx # set up ds,es to kernel space | ||
90 | mov %dx,%ds | ||
91 | mov %dx,%es | ||
92 | movl $0x17,%edx # fs points to local data space | ||
93 | mov %dx,%fs | ||
94 | call *sys_call_table(,%eax,4) | ||
95 | pushl %eax | ||
96 | movl current,%eax | ||
97 | cmpl $0,state(%eax) # state | ||
98 | jne reschedule | ||
99 | cmpl $0,counter(%eax) # counter | ||
100 | je reschedule | ||
101 | ret_from_sys_call: | ||
102 | movl current,%eax # task[0] cannot have signals | ||
103 | cmpl task,%eax | ||
104 | je 3f | ||
105 | cmpw $0x0f,CS(%esp) # was old code segment supervisor ? | ||
106 | jne 3f | ||
107 | cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ? | ||
108 | jne 3f | ||
109 | movl signal(%eax),%ebx | ||
110 | movl blocked(%eax),%ecx | ||
111 | notl %ecx | ||
112 | andl %ebx,%ecx | ||
113 | bsfl %ecx,%ecx | ||
114 | je 3f | ||
115 | btrl %ecx,%ebx | ||
116 | movl %ebx,signal(%eax) | ||
117 | incl %ecx | ||
118 | pushl %ecx | ||
119 | call do_signal | ||
120 | popl %eax | ||
121 | 3: popl %eax | ||
122 | popl %ebx | ||
123 | popl %ecx | ||
124 | popl %edx | ||
125 | pop %fs | ||
126 | pop %es | ||
127 | pop %ds | ||
128 | iret | ||
129 | |||
130 | .align 2 | ||
131 | coprocessor_error: | ||
132 | push %ds | ||
133 | push %es | ||
134 | push %fs | ||
135 | pushl %edx | ||
136 | pushl %ecx | ||
137 | pushl %ebx | ||
138 | pushl %eax | ||
139 | movl $0x10,%eax | ||
140 | mov %ax,%ds | ||
141 | mov %ax,%es | ||
142 | movl $0x17,%eax | ||
143 | mov %ax,%fs | ||
144 | pushl $ret_from_sys_call | ||
145 | jmp math_error | ||
146 | |||
147 | .align 2 | ||
148 | device_not_available: | ||
149 | push %ds | ||
150 | push %es | ||
151 | push %fs | ||
152 | pushl %edx | ||
153 | pushl %ecx | ||
154 | pushl %ebx | ||
155 | pushl %eax | ||
156 | movl $0x10,%eax | ||
157 | mov %ax,%ds | ||
158 | mov %ax,%es | ||
159 | movl $0x17,%eax | ||
160 | mov %ax,%fs | ||
161 | pushl $ret_from_sys_call | ||
162 | clts # clear TS so that we can use math | ||
163 | movl %cr0,%eax | ||
164 | testl $0x4,%eax # EM (math emulation bit) | ||
165 | je math_state_restore | ||
166 | pushl %ebp | ||
167 | pushl %esi | ||
168 | pushl %edi | ||
169 | call math_emulate | ||
170 | popl %edi | ||
171 | popl %esi | ||
172 | popl %ebp | ||
173 | ret | ||
174 | |||
175 | .align 2 | ||
176 | timer_interrupt: | ||
177 | push %ds # save ds,es and put kernel data space | ||
178 | push %es # into them. %fs is used by _system_call | ||
179 | push %fs | ||
180 | pushl %edx # we save %eax,%ecx,%edx as gcc doesn't | ||
181 | pushl %ecx # save those across function calls. %ebx | ||
182 | pushl %ebx # is saved as we use that in ret_sys_call | ||
183 | pushl %eax | ||
184 | movl $0x10,%eax | ||
185 | mov %ax,%ds | ||
186 | mov %ax,%es | ||
187 | movl $0x17,%eax | ||
188 | mov %ax,%fs | ||
189 | incl jiffies | ||
190 | movb $0x20,%al # EOI to interrupt controller #1 | ||
191 | outb %al,$0x20 | ||
192 | movl CS(%esp),%eax | ||
193 | andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor) | ||
194 | pushl %eax | ||
195 | call do_timer # 'do_timer(long CPL)' does everything from | ||
196 | addl $4,%esp # task switching to accounting ... | ||
197 | jmp ret_from_sys_call | ||
198 | |||
199 | .align 2 | ||
200 | sys_execve: | ||
201 | lea EIP(%esp),%eax | ||
202 | pushl %eax | ||
203 | call do_execve | ||
204 | addl $4,%esp | ||
205 | ret | ||
206 | |||
207 | .align 2 | ||
208 | sys_fork: | ||
209 | call find_empty_process | ||
210 | testl %eax,%eax | ||
211 | js 1f | ||
212 | push %gs | ||
213 | pushl %esi | ||
214 | pushl %edi | ||
215 | pushl %ebp | ||
216 | pushl %eax | ||
217 | call copy_process | ||
218 | addl $20,%esp | ||
219 | 1: ret | ||
220 | |||
221 | hd_interrupt: | ||
222 | pushl %eax | ||
223 | pushl %ecx | ||
224 | pushl %edx | ||
225 | push %ds | ||
226 | push %es | ||
227 | push %fs | ||
228 | movl $0x10,%eax | ||
229 | mov %ax,%ds | ||
230 | mov %ax,%es | ||
231 | movl $0x17,%eax | ||
232 | mov %ax,%fs | ||
233 | movb $0x20,%al | ||
234 | outb %al,$0xA0 # EOI to interrupt controller #1 | ||
235 | jmp 1f # give port chance to breathe | ||
236 | 1: jmp 1f | ||
237 | 1: xorl %edx,%edx | ||
238 | xchgl do_hd,%edx | ||
239 | testl %edx,%edx | ||
240 | jne 1f | ||
241 | movl $unexpected_hd_interrupt,%edx | ||
242 | 1: outb %al,$0x20 | ||
243 | call *%edx # "interesting" way of handling intr. | ||
244 | pop %fs | ||
245 | pop %es | ||
246 | pop %ds | ||
247 | popl %edx | ||
248 | popl %ecx | ||
249 | popl %eax | ||
250 | iret | ||
251 | |||
252 | floppy_interrupt: | ||
253 | pushl %eax | ||
254 | pushl %ecx | ||
255 | pushl %edx | ||
256 | push %ds | ||
257 | push %es | ||
258 | push %fs | ||
259 | movl $0x10,%eax | ||
260 | mov %ax,%ds | ||
261 | mov %ax,%es | ||
262 | movl $0x17,%eax | ||
263 | mov %ax,%fs | ||
264 | movb $0x20,%al | ||
265 | outb %al,$0x20 # EOI to interrupt controller #1 | ||
266 | xorl %eax,%eax | ||
267 | xchgl do_floppy,%eax | ||
268 | testl %eax,%eax | ||
269 | jne 1f | ||
270 | movl $unexpected_floppy_interrupt,%eax | ||
271 | 1: call *%eax # "interesting" way of handling intr. | ||
272 | pop %fs | ||
273 | pop %es | ||
274 | pop %ds | ||
275 | popl %edx | ||
276 | popl %ecx | ||
277 | popl %eax | ||
278 | iret | ||
279 | |||
280 | parallel_interrupt: | ||
281 | pushl %eax | ||
282 | movb $0x20,%al | ||
283 | outb %al,$0x20 | ||
284 | popl %eax | ||
285 | iret | ||
diff --git a/src/kernel/traps.c b/src/kernel/traps.c new file mode 100644 index 0000000..3629a13 --- /dev/null +++ b/src/kernel/traps.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * linux/kernel/traps.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 'Traps.c' handles hardware traps and faults after we have saved some | ||
9 | * state in 'asm.s'. Currently mostly a debugging-aid, will be extended | ||
10 | * to mainly kill the offending process (probably by giving it a signal, | ||
11 | * but possibly by killing it outright if necessary). | ||
12 | */ | ||
13 | #include <string.h> | ||
14 | |||
15 | #include <linux/head.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <asm/system.h> | ||
19 | #include <asm/segment.h> | ||
20 | #include <asm/io.h> | ||
21 | |||
22 | #define get_seg_byte(seg,addr) ({ \ | ||
23 | register char __res; \ | ||
24 | __asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ | ||
25 | :"=a" (__res):"0" (seg),"m" (*(addr))); \ | ||
26 | __res;}) | ||
27 | |||
28 | #define get_seg_long(seg,addr) ({ \ | ||
29 | register unsigned long __res; \ | ||
30 | __asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ | ||
31 | :"=a" (__res):"0" (seg),"m" (*(addr))); \ | ||
32 | __res;}) | ||
33 | |||
34 | #define _fs() ({ \ | ||
35 | register unsigned short __res; \ | ||
36 | __asm__("mov %%fs,%%ax":"=a" (__res):); \ | ||
37 | __res;}) | ||
38 | |||
39 | int do_exit(long code); | ||
40 | |||
41 | void page_exception(void); | ||
42 | |||
43 | void divide_error(void); | ||
44 | void debug(void); | ||
45 | void nmi(void); | ||
46 | void int3(void); | ||
47 | void overflow(void); | ||
48 | void bounds(void); | ||
49 | void invalid_op(void); | ||
50 | void device_not_available(void); | ||
51 | void double_fault(void); | ||
52 | void coprocessor_segment_overrun(void); | ||
53 | void invalid_TSS(void); | ||
54 | void segment_not_present(void); | ||
55 | void stack_segment(void); | ||
56 | void general_protection(void); | ||
57 | void page_fault(void); | ||
58 | void coprocessor_error(void); | ||
59 | void reserved(void); | ||
60 | void parallel_interrupt(void); | ||
61 | void irq13(void); | ||
62 | |||
63 | static void die(char * str,long esp_ptr,long nr) | ||
64 | { | ||
65 | long * esp = (long *) esp_ptr; | ||
66 | int i; | ||
67 | |||
68 | printk("%s: %04x\n\r",str,nr&0xffff); | ||
69 | printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n", | ||
70 | esp[1],esp[0],esp[2],esp[4],esp[3]); | ||
71 | printk("fs: %04x\n",_fs()); | ||
72 | printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17)); | ||
73 | if (esp[4] == 0x17) { | ||
74 | printk("Stack: "); | ||
75 | for (i=0;i<4;i++) | ||
76 | printk("%p ",get_seg_long(0x17,i+(long *)esp[3])); | ||
77 | printk("\n"); | ||
78 | } | ||
79 | str(i); | ||
80 | printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i); | ||
81 | for(i=0;i<10;i++) | ||
82 | printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0]))); | ||
83 | printk("\n\r"); | ||
84 | do_exit(11); /* play segment exception */ | ||
85 | } | ||
86 | |||
87 | void do_double_fault(long esp, long error_code) | ||
88 | { | ||
89 | die("double fault",esp,error_code); | ||
90 | } | ||
91 | |||
92 | void do_general_protection(long esp, long error_code) | ||
93 | { | ||
94 | die("general protection",esp,error_code); | ||
95 | } | ||
96 | |||
97 | void do_divide_error(long esp, long error_code) | ||
98 | { | ||
99 | die("divide error",esp,error_code); | ||
100 | } | ||
101 | |||
102 | void do_int3(long * esp, long error_code, | ||
103 | long fs,long es,long ds, | ||
104 | long ebp,long esi,long edi, | ||
105 | long edx,long ecx,long ebx,long eax) | ||
106 | { | ||
107 | int tr; | ||
108 | |||
109 | __asm__("str %%ax":"=a" (tr):"0" (0)); | ||
110 | printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r", | ||
111 | eax,ebx,ecx,edx); | ||
112 | printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r", | ||
113 | esi,edi,ebp,(long) esp); | ||
114 | printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r", | ||
115 | ds,es,fs,tr); | ||
116 | printk("EIP: %8x CS: %4x EFLAGS: %8x\n\r",esp[0],esp[1],esp[2]); | ||
117 | } | ||
118 | |||
119 | void do_nmi(long esp, long error_code) | ||
120 | { | ||
121 | die("nmi",esp,error_code); | ||
122 | } | ||
123 | |||
124 | void do_debug(long esp, long error_code) | ||
125 | { | ||
126 | die("debug",esp,error_code); | ||
127 | } | ||
128 | |||
129 | void do_overflow(long esp, long error_code) | ||
130 | { | ||
131 | die("overflow",esp,error_code); | ||
132 | } | ||
133 | |||
134 | void do_bounds(long esp, long error_code) | ||
135 | { | ||
136 | die("bounds",esp,error_code); | ||
137 | } | ||
138 | |||
139 | void do_invalid_op(long esp, long error_code) | ||
140 | { | ||
141 | die("invalid operand",esp,error_code); | ||
142 | } | ||
143 | |||
144 | void do_device_not_available(long esp, long error_code) | ||
145 | { | ||
146 | die("device not available",esp,error_code); | ||
147 | } | ||
148 | |||
149 | void do_coprocessor_segment_overrun(long esp, long error_code) | ||
150 | { | ||
151 | die("coprocessor segment overrun",esp,error_code); | ||
152 | } | ||
153 | |||
154 | void do_invalid_TSS(long esp,long error_code) | ||
155 | { | ||
156 | die("invalid TSS",esp,error_code); | ||
157 | } | ||
158 | |||
159 | void do_segment_not_present(long esp,long error_code) | ||
160 | { | ||
161 | die("segment not present",esp,error_code); | ||
162 | } | ||
163 | |||
164 | void do_stack_segment(long esp,long error_code) | ||
165 | { | ||
166 | die("stack segment",esp,error_code); | ||
167 | } | ||
168 | |||
169 | void do_coprocessor_error(long esp, long error_code) | ||
170 | { | ||
171 | if (last_task_used_math != current) | ||
172 | return; | ||
173 | die("coprocessor error",esp,error_code); | ||
174 | } | ||
175 | |||
176 | void do_reserved(long esp, long error_code) | ||
177 | { | ||
178 | die("reserved (15,17-47) error",esp,error_code); | ||
179 | } | ||
180 | |||
181 | void trap_init(void) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | set_trap_gate(0,÷_error); | ||
186 | set_trap_gate(1,&debug); | ||
187 | set_trap_gate(2,&nmi); | ||
188 | set_system_gate(3,&int3); /* int3-5 can be called from all */ | ||
189 | set_system_gate(4,&overflow); | ||
190 | set_system_gate(5,&bounds); | ||
191 | set_trap_gate(6,&invalid_op); | ||
192 | set_trap_gate(7,&device_not_available); | ||
193 | set_trap_gate(8,&double_fault); | ||
194 | set_trap_gate(9,&coprocessor_segment_overrun); | ||
195 | set_trap_gate(10,&invalid_TSS); | ||
196 | set_trap_gate(11,&segment_not_present); | ||
197 | set_trap_gate(12,&stack_segment); | ||
198 | set_trap_gate(13,&general_protection); | ||
199 | set_trap_gate(14,&page_fault); | ||
200 | set_trap_gate(15,&reserved); | ||
201 | set_trap_gate(16,&coprocessor_error); | ||
202 | for (i=17;i<48;i++) | ||
203 | set_trap_gate(i,&reserved); | ||
204 | set_trap_gate(45,&irq13); | ||
205 | outb_p(inb_p(0x21)&0xfb,0x21); | ||
206 | outb(inb_p(0xA1)&0xdf,0xA1); | ||
207 | set_trap_gate(39,¶llel_interrupt); | ||
208 | } | ||
diff --git a/src/kernel/vsprintf.c b/src/kernel/vsprintf.c new file mode 100644 index 0000000..ab70f23 --- /dev/null +++ b/src/kernel/vsprintf.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * linux/kernel/vsprintf.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ | ||
8 | /* | ||
9 | * Wirzenius wrote this portably, Torvalds fucked it up :-) | ||
10 | */ | ||
11 | |||
12 | #include <stdarg.h> | ||
13 | #include <string.h> | ||
14 | |||
15 | /* we use this so that we can do without the ctype library */ | ||
16 | #define is_digit(c) ((c) >= '0' && (c) <= '9') | ||
17 | |||
18 | static int skip_atoi(const char **s) | ||
19 | { | ||
20 | int i=0; | ||
21 | |||
22 | while (is_digit(**s)) | ||
23 | i = i*10 + *((*s)++) - '0'; | ||
24 | return i; | ||
25 | } | ||
26 | |||
27 | #define ZEROPAD 1 /* pad with zero */ | ||
28 | #define SIGN 2 /* unsigned/signed long */ | ||
29 | #define PLUS 4 /* show plus */ | ||
30 | #define SPACE 8 /* space if plus */ | ||
31 | #define LEFT 16 /* left justified */ | ||
32 | #define SPECIAL 32 /* 0x */ | ||
33 | #define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ | ||
34 | |||
35 | #define do_div(n,base) ({ \ | ||
36 | int __res; \ | ||
37 | __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ | ||
38 | __res; }) | ||
39 | |||
40 | static char * number(char * str, int num, int base, int size, int precision | ||
41 | ,int type) | ||
42 | { | ||
43 | char c,sign,tmp[36]; | ||
44 | const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||
45 | int i; | ||
46 | |||
47 | if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; | ||
48 | if (type&LEFT) type &= ~ZEROPAD; | ||
49 | if (base<2 || base>36) | ||
50 | return 0; | ||
51 | c = (type & ZEROPAD) ? '0' : ' ' ; | ||
52 | if (type&SIGN && num<0) { | ||
53 | sign='-'; | ||
54 | num = -num; | ||
55 | } else | ||
56 | sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); | ||
57 | if (sign) size--; | ||
58 | if (type&SPECIAL) { | ||
59 | if (base==16) size -= 2; | ||
60 | else if (base==8) size--; | ||
61 | } | ||
62 | i=0; | ||
63 | if (num==0) | ||
64 | tmp[i++]='0'; | ||
65 | else while (num!=0) | ||
66 | tmp[i++]=digits[do_div(num,base)]; | ||
67 | if (i>precision) precision=i; | ||
68 | size -= precision; | ||
69 | if (!(type&(ZEROPAD+LEFT))) | ||
70 | while(size-->0) | ||
71 | *str++ = ' '; | ||
72 | if (sign) | ||
73 | *str++ = sign; | ||
74 | if (type&SPECIAL) { | ||
75 | if (base==8) | ||
76 | *str++ = '0'; | ||
77 | else if (base==16) { | ||
78 | *str++ = '0'; | ||
79 | *str++ = digits[33]; | ||
80 | } | ||
81 | } | ||
82 | if (!(type&LEFT)) | ||
83 | while(size-->0) | ||
84 | *str++ = c; | ||
85 | while(i<precision--) | ||
86 | *str++ = '0'; | ||
87 | while(i-->0) | ||
88 | *str++ = tmp[i]; | ||
89 | while(size-->0) | ||
90 | *str++ = ' '; | ||
91 | return str; | ||
92 | } | ||
93 | |||
94 | int vsprintf(char *buf, const char *fmt, va_list args) | ||
95 | { | ||
96 | int len; | ||
97 | int i; | ||
98 | char * str; | ||
99 | char *s; | ||
100 | int *ip; | ||
101 | |||
102 | int flags; /* flags to number() */ | ||
103 | |||
104 | int field_width; /* width of output field */ | ||
105 | int precision; /* min. # of digits for integers; max | ||
106 | number of chars for from string */ | ||
107 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ | ||
108 | |||
109 | for (str=buf ; *fmt ; ++fmt) { | ||
110 | if (*fmt != '%') { | ||
111 | *str++ = *fmt; | ||
112 | continue; | ||
113 | } | ||
114 | |||
115 | /* process flags */ | ||
116 | flags = 0; | ||
117 | repeat: | ||
118 | ++fmt; /* this also skips first '%' */ | ||
119 | switch (*fmt) { | ||
120 | case '-': flags |= LEFT; goto repeat; | ||
121 | case '+': flags |= PLUS; goto repeat; | ||
122 | case ' ': flags |= SPACE; goto repeat; | ||
123 | case '#': flags |= SPECIAL; goto repeat; | ||
124 | case '0': flags |= ZEROPAD; goto repeat; | ||
125 | } | ||
126 | |||
127 | /* get field width */ | ||
128 | field_width = -1; | ||
129 | if (is_digit(*fmt)) | ||
130 | field_width = skip_atoi(&fmt); | ||
131 | else if (*fmt == '*') { | ||
132 | /* it's the next argument */ | ||
133 | field_width = va_arg(args, int); | ||
134 | if (field_width < 0) { | ||
135 | field_width = -field_width; | ||
136 | flags |= LEFT; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /* get the precision */ | ||
141 | precision = -1; | ||
142 | if (*fmt == '.') { | ||
143 | ++fmt; | ||
144 | if (is_digit(*fmt)) | ||
145 | precision = skip_atoi(&fmt); | ||
146 | else if (*fmt == '*') { | ||
147 | /* it's the next argument */ | ||
148 | precision = va_arg(args, int); | ||
149 | } | ||
150 | if (precision < 0) | ||
151 | precision = 0; | ||
152 | } | ||
153 | |||
154 | /* get the conversion qualifier */ | ||
155 | qualifier = -1; | ||
156 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { | ||
157 | qualifier = *fmt; | ||
158 | ++fmt; | ||
159 | } | ||
160 | |||
161 | switch (*fmt) { | ||
162 | case 'c': | ||
163 | if (!(flags & LEFT)) | ||
164 | while (--field_width > 0) | ||
165 | *str++ = ' '; | ||
166 | *str++ = (unsigned char) va_arg(args, int); | ||
167 | while (--field_width > 0) | ||
168 | *str++ = ' '; | ||
169 | break; | ||
170 | |||
171 | case 's': | ||
172 | s = va_arg(args, char *); | ||
173 | len = strlen(s); | ||
174 | if (precision < 0) | ||
175 | precision = len; | ||
176 | else if (len > precision) | ||
177 | len = precision; | ||
178 | |||
179 | if (!(flags & LEFT)) | ||
180 | while (len < field_width--) | ||
181 | *str++ = ' '; | ||
182 | for (i = 0; i < len; ++i) | ||
183 | *str++ = *s++; | ||
184 | while (len < field_width--) | ||
185 | *str++ = ' '; | ||
186 | break; | ||
187 | |||
188 | case 'o': | ||
189 | str = number(str, va_arg(args, unsigned long), 8, | ||
190 | field_width, precision, flags); | ||
191 | break; | ||
192 | |||
193 | case 'p': | ||
194 | if (field_width == -1) { | ||
195 | field_width = 8; | ||
196 | flags |= ZEROPAD; | ||
197 | } | ||
198 | str = number(str, | ||
199 | (unsigned long) va_arg(args, void *), 16, | ||
200 | field_width, precision, flags); | ||
201 | break; | ||
202 | |||
203 | case 'x': | ||
204 | flags |= SMALL; | ||
205 | case 'X': | ||
206 | str = number(str, va_arg(args, unsigned long), 16, | ||
207 | field_width, precision, flags); | ||
208 | break; | ||
209 | |||
210 | case 'd': | ||
211 | case 'i': | ||
212 | flags |= SIGN; | ||
213 | case 'u': | ||
214 | str = number(str, va_arg(args, unsigned long), 10, | ||
215 | field_width, precision, flags); | ||
216 | break; | ||
217 | |||
218 | case 'n': | ||
219 | ip = va_arg(args, int *); | ||
220 | *ip = (str - buf); | ||
221 | break; | ||
222 | |||
223 | default: | ||
224 | if (*fmt != '%') | ||
225 | *str++ = '%'; | ||
226 | if (*fmt) | ||
227 | *str++ = *fmt; | ||
228 | else | ||
229 | --fmt; | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | *str = '\0'; | ||
234 | return str-buf; | ||
235 | } | ||
diff --git a/src/lib/Makefile b/src/lib/Makefile new file mode 100644 index 0000000..2ac16b0 --- /dev/null +++ b/src/lib/Makefile | |||
@@ -0,0 +1,69 @@ | |||
1 | # | ||
2 | # Makefile for some libs needed in the kernel. | ||
3 | # | ||
4 | # Note! Dependencies are done automagically by 'make dep', which also | ||
5 | # removes any old dependencies. DON'T put your own dependencies here | ||
6 | # unless it's something special (ie not a .c file). | ||
7 | # | ||
8 | |||
9 | include ../Makefile.header | ||
10 | |||
11 | CFLAGS += -I../include | ||
12 | CPP += -I../include | ||
13 | |||
14 | .c.s: | ||
15 | @$(CC) $(CFLAGS) \ | ||
16 | -S -o $*.s $< | ||
17 | .s.o: | ||
18 | @$(AS) -o $*.o $< | ||
19 | .c.o: | ||
20 | @$(CC) $(CFLAGS) \ | ||
21 | -c -o $*.o $< | ||
22 | |||
23 | OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \ | ||
24 | execve.o wait.o string.o malloc.o | ||
25 | |||
26 | lib.a: $(OBJS) | ||
27 | @$(AR) rcs lib.a $(OBJS) | ||
28 | @sync | ||
29 | |||
30 | clean: | ||
31 | @rm -f core *.o *.a tmp_make | ||
32 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
33 | |||
34 | dep: | ||
35 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
36 | @(for i in *.c;do echo -n `echo $$i | sed 's,\.c,\.s,'`" "; \ | ||
37 | $(CPP) -M $$i;done) >> tmp_make | ||
38 | @cp tmp_make Makefile | ||
39 | |||
40 | ### Dependencies: | ||
41 | _exit.s _exit.o : _exit.c ../include/unistd.h ../include/sys/stat.h \ | ||
42 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
43 | ../include/utime.h | ||
44 | close.s close.o : close.c ../include/unistd.h ../include/sys/stat.h \ | ||
45 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
46 | ../include/utime.h | ||
47 | ctype.s ctype.o : ctype.c ../include/ctype.h | ||
48 | dup.s dup.o : dup.c ../include/unistd.h ../include/sys/stat.h \ | ||
49 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
50 | ../include/utime.h | ||
51 | errno.s errno.o : errno.c | ||
52 | execve.s execve.o : execve.c ../include/unistd.h ../include/sys/stat.h \ | ||
53 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
54 | ../include/utime.h | ||
55 | malloc.s malloc.o : malloc.c ../include/linux/kernel.h ../include/linux/mm.h \ | ||
56 | ../include/asm/system.h | ||
57 | open.s open.o : open.c ../include/unistd.h ../include/sys/stat.h \ | ||
58 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
59 | ../include/utime.h ../include/stdarg.h | ||
60 | setsid.s setsid.o : setsid.c ../include/unistd.h ../include/sys/stat.h \ | ||
61 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
62 | ../include/utime.h | ||
63 | string.s string.o : string.c ../include/string.h | ||
64 | wait.s wait.o : wait.c ../include/unistd.h ../include/sys/stat.h \ | ||
65 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
66 | ../include/utime.h ../include/sys/wait.h | ||
67 | write.s write.o : write.c ../include/unistd.h ../include/sys/stat.h \ | ||
68 | ../include/sys/types.h ../include/sys/times.h ../include/sys/utsname.h \ | ||
69 | ../include/utime.h | ||
diff --git a/src/lib/_exit.c b/src/lib/_exit.c new file mode 100644 index 0000000..09e31f6 --- /dev/null +++ b/src/lib/_exit.c | |||
@@ -0,0 +1,13 @@ | |||
1 | /* | ||
2 | * linux/lib/_exit.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | |||
10 | void _exit(int exit_code) | ||
11 | { | ||
12 | __asm__ __volatile__ ("int $0x80"::"a" (__NR_exit),"b" (exit_code)); | ||
13 | } | ||
diff --git a/src/lib/close.c b/src/lib/close.c new file mode 100644 index 0000000..afd8364 --- /dev/null +++ b/src/lib/close.c | |||
@@ -0,0 +1,10 @@ | |||
1 | /* | ||
2 | * linux/lib/close.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | |||
10 | _syscall1(int,close,int,fd) | ||
diff --git a/src/lib/ctype.c b/src/lib/ctype.c new file mode 100644 index 0000000..877e629 --- /dev/null +++ b/src/lib/ctype.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * linux/lib/ctype.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #include <ctype.h> | ||
8 | |||
9 | char _ctmp; | ||
10 | unsigned char _ctype[] = {0x00, /* EOF */ | ||
11 | _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ | ||
12 | _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ | ||
13 | _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ | ||
14 | _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ | ||
15 | _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ | ||
16 | _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ | ||
17 | _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ | ||
18 | _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ | ||
19 | _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ | ||
20 | _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ | ||
21 | _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ | ||
22 | _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ | ||
23 | _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ | ||
24 | _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ | ||
25 | _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ | ||
26 | _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ | ||
27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ | ||
28 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ | ||
29 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ | ||
30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ | ||
31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ | ||
32 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ | ||
33 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ | ||
34 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ | ||
35 | |||
diff --git a/src/lib/dup.c b/src/lib/dup.c new file mode 100644 index 0000000..dd13414 --- /dev/null +++ b/src/lib/dup.c | |||
@@ -0,0 +1,10 @@ | |||
1 | /* | ||
2 | * linux/lib/dup.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | |||
10 | _syscall1(int,dup,int,fd) | ||
diff --git a/src/lib/errno.c b/src/lib/errno.c new file mode 100644 index 0000000..50aca2e --- /dev/null +++ b/src/lib/errno.c | |||
@@ -0,0 +1,7 @@ | |||
1 | /* | ||
2 | * linux/lib/errno.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | int errno; | ||
diff --git a/src/lib/execve.c b/src/lib/execve.c new file mode 100644 index 0000000..a89726d --- /dev/null +++ b/src/lib/execve.c | |||
@@ -0,0 +1,10 @@ | |||
1 | /* | ||
2 | * linux/lib/execve.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | |||
10 | _syscall3(int,execve,const char *,file,char **,argv,char **,envp) | ||
diff --git a/src/lib/malloc.c b/src/lib/malloc.c new file mode 100644 index 0000000..ef7abf3 --- /dev/null +++ b/src/lib/malloc.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * malloc.c --- a general purpose kernel memory allocator for Linux. | ||
3 | * | ||
4 | * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91 | ||
5 | * | ||
6 | * This routine is written to be as fast as possible, so that it | ||
7 | * can be called from the interrupt level. | ||
8 | * | ||
9 | * Limitations: maximum size of memory we can allocate using this routine | ||
10 | * is 4k, the size of a page in Linux. | ||
11 | * | ||
12 | * The general game plan is that each page (called a bucket) will only hold | ||
13 | * objects of a given size. When all of the object on a page are released, | ||
14 | * the page can be returned to the general free pool. When malloc() is | ||
15 | * called, it looks for the smallest bucket size which will fulfill its | ||
16 | * request, and allocate a piece of memory from that bucket pool. | ||
17 | * | ||
18 | * Each bucket has as its control block a bucket descriptor which keeps | ||
19 | * track of how many objects are in use on that page, and the free list | ||
20 | * for that page. Like the buckets themselves, bucket descriptors are | ||
21 | * stored on pages requested from get_free_page(). However, unlike buckets, | ||
22 | * pages devoted to bucket descriptor pages are never released back to the | ||
23 | * system. Fortunately, a system should probably only need 1 or 2 bucket | ||
24 | * descriptor pages, since a page can hold 256 bucket descriptors (which | ||
25 | * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using | ||
26 | * that much allocated memory, it's probably doing something wrong. :-) | ||
27 | * | ||
28 | * Note: malloc() and free() both call get_free_page() and free_page() | ||
29 | * in sections of code where interrupts are turned off, to allow | ||
30 | * malloc() and free() to be safely called from an interrupt routine. | ||
31 | * (We will probably need this functionality when networking code, | ||
32 | * particularily things like NFS, is added to Linux.) However, this | ||
33 | * presumes that get_free_page() and free_page() are interrupt-level | ||
34 | * safe, which they may not be once paging is added. If this is the | ||
35 | * case, we will need to modify malloc() to keep a few unused pages | ||
36 | * "pre-allocated" so that it can safely draw upon those pages if | ||
37 | * it is called from an interrupt routine. | ||
38 | * | ||
39 | * Another concern is that get_free_page() should not sleep; if it | ||
40 | * does, the code is carefully ordered so as to avoid any race | ||
41 | * conditions. The catch is that if malloc() is called re-entrantly, | ||
42 | * there is a chance that unecessary pages will be grabbed from the | ||
43 | * system. Except for the pages for the bucket descriptor page, the | ||
44 | * extra pages will eventually get released back to the system, though, | ||
45 | * so it isn't all that bad. | ||
46 | */ | ||
47 | |||
48 | #include <linux/kernel.h> | ||
49 | #include <linux/mm.h> | ||
50 | #include <asm/system.h> | ||
51 | |||
52 | struct bucket_desc { /* 16 bytes */ | ||
53 | void *page; | ||
54 | struct bucket_desc *next; | ||
55 | void *freeptr; | ||
56 | unsigned short refcnt; | ||
57 | unsigned short bucket_size; | ||
58 | }; | ||
59 | |||
60 | struct _bucket_dir { /* 8 bytes */ | ||
61 | int size; | ||
62 | struct bucket_desc *chain; | ||
63 | }; | ||
64 | |||
65 | /* | ||
66 | * The following is the where we store a pointer to the first bucket | ||
67 | * descriptor for a given size. | ||
68 | * | ||
69 | * If it turns out that the Linux kernel allocates a lot of objects of a | ||
70 | * specific size, then we may want to add that specific size to this list, | ||
71 | * since that will allow the memory to be allocated more efficiently. | ||
72 | * However, since an entire page must be dedicated to each specific size | ||
73 | * on this list, some amount of temperance must be exercised here. | ||
74 | * | ||
75 | * Note that this list *must* be kept in order. | ||
76 | */ | ||
77 | struct _bucket_dir bucket_dir[] = { | ||
78 | { 16, (struct bucket_desc *) 0}, | ||
79 | { 32, (struct bucket_desc *) 0}, | ||
80 | { 64, (struct bucket_desc *) 0}, | ||
81 | { 128, (struct bucket_desc *) 0}, | ||
82 | { 256, (struct bucket_desc *) 0}, | ||
83 | { 512, (struct bucket_desc *) 0}, | ||
84 | { 1024, (struct bucket_desc *) 0}, | ||
85 | { 2048, (struct bucket_desc *) 0}, | ||
86 | { 4096, (struct bucket_desc *) 0}, | ||
87 | { 0, (struct bucket_desc *) 0}}; /* End of list marker */ | ||
88 | |||
89 | /* | ||
90 | * This contains a linked list of free bucket descriptor blocks | ||
91 | */ | ||
92 | struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0; | ||
93 | |||
94 | /* | ||
95 | * This routine initializes a bucket description page. | ||
96 | */ | ||
97 | static inline void init_bucket_desc() | ||
98 | { | ||
99 | struct bucket_desc *bdesc, *first; | ||
100 | int i; | ||
101 | |||
102 | first = bdesc = (struct bucket_desc *) get_free_page(); | ||
103 | if (!bdesc) | ||
104 | panic("Out of memory in init_bucket_desc()"); | ||
105 | for (i = PAGE_SIZE/sizeof(struct bucket_desc); i > 1; i--) { | ||
106 | bdesc->next = bdesc+1; | ||
107 | bdesc++; | ||
108 | } | ||
109 | /* | ||
110 | * This is done last, to avoid race conditions in case | ||
111 | * get_free_page() sleeps and this routine gets called again.... | ||
112 | */ | ||
113 | bdesc->next = free_bucket_desc; | ||
114 | free_bucket_desc = first; | ||
115 | } | ||
116 | |||
117 | void *malloc(unsigned int len) | ||
118 | { | ||
119 | struct _bucket_dir *bdir; | ||
120 | struct bucket_desc *bdesc; | ||
121 | void *retval; | ||
122 | |||
123 | /* | ||
124 | * First we search the bucket_dir to find the right bucket change | ||
125 | * for this request. | ||
126 | */ | ||
127 | for (bdir = bucket_dir; bdir->size; bdir++) | ||
128 | if (bdir->size >= len) | ||
129 | break; | ||
130 | if (!bdir->size) { | ||
131 | printk("malloc called with impossibly large argument (%d)\n", | ||
132 | len); | ||
133 | panic("malloc: bad arg"); | ||
134 | } | ||
135 | /* | ||
136 | * Now we search for a bucket descriptor which has free space | ||
137 | */ | ||
138 | cli(); /* Avoid race conditions */ | ||
139 | for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) | ||
140 | if (bdesc->freeptr) | ||
141 | break; | ||
142 | /* | ||
143 | * If we didn't find a bucket with free space, then we'll | ||
144 | * allocate a new one. | ||
145 | */ | ||
146 | if (!bdesc) { | ||
147 | char *cp; | ||
148 | int i; | ||
149 | |||
150 | if (!free_bucket_desc) | ||
151 | init_bucket_desc(); | ||
152 | bdesc = free_bucket_desc; | ||
153 | free_bucket_desc = bdesc->next; | ||
154 | bdesc->refcnt = 0; | ||
155 | bdesc->bucket_size = bdir->size; | ||
156 | bdesc->page = bdesc->freeptr = (void *) (cp = (char *) get_free_page()); | ||
157 | if (!cp) | ||
158 | panic("Out of memory in kernel malloc()"); | ||
159 | /* Set up the chain of free objects */ | ||
160 | for (i=PAGE_SIZE/bdir->size; i > 1; i--) { | ||
161 | *((char **) cp) = cp + bdir->size; | ||
162 | cp += bdir->size; | ||
163 | } | ||
164 | *((char **) cp) = 0; | ||
165 | bdesc->next = bdir->chain; /* OK, link it in! */ | ||
166 | bdir->chain = bdesc; | ||
167 | } | ||
168 | retval = (void *) bdesc->freeptr; | ||
169 | bdesc->freeptr = *((void **) retval); | ||
170 | bdesc->refcnt++; | ||
171 | sti(); /* OK, we're safe again */ | ||
172 | return(retval); | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * Here is the free routine. If you know the size of the object that you | ||
177 | * are freeing, then free_s() will use that information to speed up the | ||
178 | * search for the bucket descriptor. | ||
179 | * | ||
180 | * We will #define a macro so that "free(x)" is becomes "free_s(x, 0)" | ||
181 | */ | ||
182 | void free_s(void *obj, int size) | ||
183 | { | ||
184 | void *page; | ||
185 | struct _bucket_dir *bdir; | ||
186 | struct bucket_desc *bdesc, *prev; | ||
187 | bdesc = prev = 0; | ||
188 | /* Calculate what page this object lives in */ | ||
189 | page = (void *) ((unsigned long) obj & 0xfffff000); | ||
190 | /* Now search the buckets looking for that page */ | ||
191 | for (bdir = bucket_dir; bdir->size; bdir++) { | ||
192 | prev = 0; | ||
193 | /* If size is zero then this conditional is always false */ | ||
194 | if (bdir->size < size) | ||
195 | continue; | ||
196 | for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { | ||
197 | if (bdesc->page == page) | ||
198 | goto found; | ||
199 | prev = bdesc; | ||
200 | } | ||
201 | } | ||
202 | panic("Bad address passed to kernel free_s()"); | ||
203 | found: | ||
204 | cli(); /* To avoid race conditions */ | ||
205 | *((void **)obj) = bdesc->freeptr; | ||
206 | bdesc->freeptr = obj; | ||
207 | bdesc->refcnt--; | ||
208 | if (bdesc->refcnt == 0) { | ||
209 | /* | ||
210 | * We need to make sure that prev is still accurate. It | ||
211 | * may not be, if someone rudely interrupted us.... | ||
212 | */ | ||
213 | if ((prev && (prev->next != bdesc)) || | ||
214 | (!prev && (bdir->chain != bdesc))) | ||
215 | for (prev = bdir->chain; prev; prev = prev->next) | ||
216 | if (prev->next == bdesc) | ||
217 | break; | ||
218 | if (prev) | ||
219 | prev->next = bdesc->next; | ||
220 | else { | ||
221 | if (bdir->chain != bdesc) | ||
222 | panic("malloc bucket chains corrupted"); | ||
223 | bdir->chain = bdesc->next; | ||
224 | } | ||
225 | free_page((unsigned long) bdesc->page); | ||
226 | bdesc->next = free_bucket_desc; | ||
227 | free_bucket_desc = bdesc; | ||
228 | } | ||
229 | sti(); | ||
230 | return; | ||
231 | } | ||
232 | |||
diff --git a/src/lib/open.c b/src/lib/open.c new file mode 100644 index 0000000..8c3fc58 --- /dev/null +++ b/src/lib/open.c | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/lib/open.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | #include <stdarg.h> | ||
10 | |||
11 | int open(const char * filename, int flag, ...) | ||
12 | { | ||
13 | register int res; | ||
14 | va_list arg; | ||
15 | |||
16 | va_start(arg,flag); | ||
17 | __asm__("int $0x80" | ||
18 | :"=a" (res) | ||
19 | :"0" (__NR_open),"b" (filename),"c" (flag), | ||
20 | "d" (va_arg(arg,int))); | ||
21 | if (res>=0) | ||
22 | return res; | ||
23 | errno = -res; | ||
24 | return -1; | ||
25 | } | ||
diff --git a/src/lib/setsid.c b/src/lib/setsid.c new file mode 100644 index 0000000..68516c7 --- /dev/null +++ b/src/lib/setsid.c | |||
@@ -0,0 +1,10 @@ | |||
1 | /* | ||
2 | * linux/lib/setsid.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | |||
10 | _syscall0(pid_t,setsid) | ||
diff --git a/src/lib/string.c b/src/lib/string.c new file mode 100644 index 0000000..cca9e60 --- /dev/null +++ b/src/lib/string.c | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | * linux/lib/string.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #ifndef __GNUC__ | ||
8 | #error I want gcc! | ||
9 | #endif | ||
10 | |||
11 | #define extern | ||
12 | #define inline | ||
13 | #define static | ||
14 | #define __LIBRARY__ | ||
15 | #include <string.h> | ||
16 | |||
17 | inline char * strcpy(char * dest,const char *src) | ||
18 | { | ||
19 | __asm__("cld\n" | ||
20 | "1:\tlodsb\n\t" | ||
21 | "stosb\n\t" | ||
22 | "testb %%al,%%al\n\t" | ||
23 | "jne 1b" | ||
24 | ::"S" (src),"D" (dest)); | ||
25 | return dest; | ||
26 | } | ||
27 | |||
28 | static inline char * strncpy(char * dest,const char *src,int count) | ||
29 | { | ||
30 | __asm__("cld\n" | ||
31 | "1:\tdecl %2\n\t" | ||
32 | "js 2f\n\t" | ||
33 | "lodsb\n\t" | ||
34 | "stosb\n\t" | ||
35 | "testb %%al,%%al\n\t" | ||
36 | "jne 1b\n\t" | ||
37 | "rep\n\t" | ||
38 | "stosb\n" | ||
39 | "2:" | ||
40 | ::"S" (src),"D" (dest),"c" (count)); | ||
41 | return dest; | ||
42 | } | ||
43 | |||
44 | inline char * strcat(char * dest,const char * src) | ||
45 | { | ||
46 | __asm__("cld\n\t" | ||
47 | "repne\n\t" | ||
48 | "scasb\n\t" | ||
49 | "decl %1\n" | ||
50 | "1:\tlodsb\n\t" | ||
51 | "stosb\n\t" | ||
52 | "testb %%al,%%al\n\t" | ||
53 | "jne 1b" | ||
54 | ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff)); | ||
55 | return dest; | ||
56 | } | ||
57 | |||
58 | static inline char * strncat(char * dest,const char * src,int count) | ||
59 | { | ||
60 | __asm__("cld\n\t" | ||
61 | "repne\n\t" | ||
62 | "scasb\n\t" | ||
63 | "decl %1\n\t" | ||
64 | "movl %4,%3\n" | ||
65 | "1:\tdecl %3\n\t" | ||
66 | "js 2f\n\t" | ||
67 | "lodsb\n\t" | ||
68 | "stosb\n\t" | ||
69 | "testb %%al,%%al\n\t" | ||
70 | "jne 1b\n" | ||
71 | "2:\txorl %2,%2\n\t" | ||
72 | "stosb" | ||
73 | ::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count) | ||
74 | ); | ||
75 | return dest; | ||
76 | } | ||
77 | |||
78 | inline int strcmp(const char * cs,const char * ct) | ||
79 | { | ||
80 | register int __res ; | ||
81 | __asm__("cld\n" | ||
82 | "1:\tlodsb\n\t" | ||
83 | "scasb\n\t" | ||
84 | "jne 2f\n\t" | ||
85 | "testb %%al,%%al\n\t" | ||
86 | "jne 1b\n\t" | ||
87 | "xorl %%eax,%%eax\n\t" | ||
88 | "jmp 3f\n" | ||
89 | "2:\tmovl $1,%%eax\n\t" | ||
90 | "jl 3f\n\t" | ||
91 | "negl %%eax\n" | ||
92 | "3:" | ||
93 | :"=a" (__res):"D" (cs),"S" (ct)); | ||
94 | return __res; | ||
95 | } | ||
96 | |||
97 | |||
98 | static inline int strncmp(const char * cs,const char * ct,int count) | ||
99 | { | ||
100 | register int __res ; | ||
101 | __asm__("cld\n" | ||
102 | "1:\tdecl %3\n\t" | ||
103 | "js 2f\n\t" | ||
104 | "lodsb\n\t" | ||
105 | "scasb\n\t" | ||
106 | "jne 3f\n\t" | ||
107 | "testb %%al,%%al\n\t" | ||
108 | "jne 1b\n" | ||
109 | "2:\txorl %%eax,%%eax\n\t" | ||
110 | "jmp 4f\n" | ||
111 | "3:\tmovl $1,%%eax\n\t" | ||
112 | "jl 4f\n\t" | ||
113 | "negl %%eax\n" | ||
114 | "4:" | ||
115 | :"=a" (__res):"D" (cs),"S" (ct),"c" (count)); | ||
116 | return __res; | ||
117 | } | ||
118 | |||
119 | static inline char * strchr(const char * s,char c) | ||
120 | { | ||
121 | register char * __res ; | ||
122 | __asm__("cld\n\t" | ||
123 | "movb %%al,%%ah\n" | ||
124 | "1:\tlodsb\n\t" | ||
125 | "cmpb %%ah,%%al\n\t" | ||
126 | "je 2f\n\t" | ||
127 | "testb %%al,%%al\n\t" | ||
128 | "jne 1b\n\t" | ||
129 | "movl $1,%1\n" | ||
130 | "2:\tmovl %1,%0\n\t" | ||
131 | "decl %0" | ||
132 | :"=a" (__res):"S" (s),"0" (c)); | ||
133 | return __res; | ||
134 | } | ||
135 | |||
136 | static inline char * strrchr(const char * s,char c) | ||
137 | { | ||
138 | register char * __res; | ||
139 | __asm__("cld\n\t" | ||
140 | "movb %%al,%%ah\n" | ||
141 | "1:\tlodsb\n\t" | ||
142 | "cmpb %%ah,%%al\n\t" | ||
143 | "jne 2f\n\t" | ||
144 | "movl %%esi,%0\n\t" | ||
145 | "decl %0\n" | ||
146 | "2:\ttestb %%al,%%al\n\t" | ||
147 | "jne 1b" | ||
148 | :"=d" (__res):"0" (0),"S" (s),"a" (c)); | ||
149 | return __res; | ||
150 | } | ||
151 | |||
152 | inline int strspn(const char * cs, const char * ct) | ||
153 | { | ||
154 | register char * __res; | ||
155 | __asm__("cld\n\t" | ||
156 | "movl %4,%%edi\n\t" | ||
157 | "repne\n\t" | ||
158 | "scasb\n\t" | ||
159 | "notl %%ecx\n\t" | ||
160 | "decl %%ecx\n\t" | ||
161 | "movl %%ecx,%%edx\n" | ||
162 | "1:\tlodsb\n\t" | ||
163 | "testb %%al,%%al\n\t" | ||
164 | "je 2f\n\t" | ||
165 | "movl %4,%%edi\n\t" | ||
166 | "movl %%edx,%%ecx\n\t" | ||
167 | "repne\n\t" | ||
168 | "scasb\n\t" | ||
169 | "je 1b\n" | ||
170 | "2:\tdecl %0" | ||
171 | :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) | ||
172 | ); | ||
173 | return __res-cs; | ||
174 | } | ||
175 | |||
176 | inline int strcspn(const char * cs, const char * ct) | ||
177 | { | ||
178 | register char * __res; | ||
179 | __asm__("cld\n\t" | ||
180 | "movl %4,%%edi\n\t" | ||
181 | "repne\n\t" | ||
182 | "scasb\n\t" | ||
183 | "notl %%ecx\n\t" | ||
184 | "decl %%ecx\n\t" | ||
185 | "movl %%ecx,%%edx\n" | ||
186 | "1:\tlodsb\n\t" | ||
187 | "testb %%al,%%al\n\t" | ||
188 | "je 2f\n\t" | ||
189 | "movl %4,%%edi\n\t" | ||
190 | "movl %%edx,%%ecx\n\t" | ||
191 | "repne\n\t" | ||
192 | "scasb\n\t" | ||
193 | "jne 1b\n" | ||
194 | "2:\tdecl %0" | ||
195 | :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) | ||
196 | ); | ||
197 | return __res-cs; | ||
198 | } | ||
199 | |||
200 | inline char * strpbrk(const char * cs,const char * ct) | ||
201 | { | ||
202 | register char * __res ; | ||
203 | __asm__("cld\n\t" | ||
204 | "movl %4,%%edi\n\t" | ||
205 | "repne\n\t" | ||
206 | "scasb\n\t" | ||
207 | "notl %%ecx\n\t" | ||
208 | "decl %%ecx\n\t" | ||
209 | "movl %%ecx,%%edx\n" | ||
210 | "1:\tlodsb\n\t" | ||
211 | "testb %%al,%%al\n\t" | ||
212 | "je 2f\n\t" | ||
213 | "movl %4,%%edi\n\t" | ||
214 | "movl %%edx,%%ecx\n\t" | ||
215 | "repne\n\t" | ||
216 | "scasb\n\t" | ||
217 | "jne 1b\n\t" | ||
218 | "decl %0\n\t" | ||
219 | "jmp 3f\n" | ||
220 | "2:\txorl %0,%0\n" | ||
221 | "3:" | ||
222 | :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) | ||
223 | ); | ||
224 | return __res; | ||
225 | } | ||
226 | |||
227 | inline char * strstr(const char * cs,const char * ct) | ||
228 | { | ||
229 | register char * __res ; | ||
230 | __asm__("cld\n\t" \ | ||
231 | "movl %4,%%edi\n\t" | ||
232 | "repne\n\t" | ||
233 | "scasb\n\t" | ||
234 | "notl %%ecx\n\t" | ||
235 | "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ | ||
236 | "movl %%ecx,%%edx\n" | ||
237 | "1:\tmovl %4,%%edi\n\t" | ||
238 | "movl %%esi,%%eax\n\t" | ||
239 | "movl %%edx,%%ecx\n\t" | ||
240 | "repe\n\t" | ||
241 | "cmpsb\n\t" | ||
242 | "je 2f\n\t" /* also works for empty string, see above */ | ||
243 | "xchgl %%eax,%%esi\n\t" | ||
244 | "incl %%esi\n\t" | ||
245 | "cmpb $0,-1(%%eax)\n\t" | ||
246 | "jne 1b\n\t" | ||
247 | "xorl %%eax,%%eax\n\t" | ||
248 | "2:" | ||
249 | :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct) | ||
250 | ); | ||
251 | return __res; | ||
252 | } | ||
253 | |||
254 | inline int strlen(const char * s) | ||
255 | { | ||
256 | register int __res ; | ||
257 | __asm__("cld\n\t" | ||
258 | "repne\n\t" | ||
259 | "scasb\n\t" | ||
260 | "notl %0\n\t" | ||
261 | "decl %0" | ||
262 | :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff)); | ||
263 | return __res; | ||
264 | } | ||
265 | |||
266 | inline char * strtok(char * s,const char * ct) | ||
267 | { | ||
268 | register char * __res ; | ||
269 | __asm__("testl %1,%1\n\t" | ||
270 | "jne 1f\n\t" | ||
271 | "testl %0,%0\n\t" | ||
272 | "je 8f\n\t" | ||
273 | "movl %0,%1\n" | ||
274 | "1:\txorl %0,%0\n\t" | ||
275 | "movl $-1,%%ecx\n\t" | ||
276 | "xorl %%eax,%%eax\n\t" | ||
277 | "cld\n\t" | ||
278 | "movl %4,%%edi\n\t" | ||
279 | "repne\n\t" | ||
280 | "scasb\n\t" | ||
281 | "notl %%ecx\n\t" | ||
282 | "decl %%ecx\n\t" | ||
283 | "je 7f\n\t" /* empty delimeter-string */ | ||
284 | "movl %%ecx,%%edx\n" | ||
285 | "2:\tlodsb\n\t" | ||
286 | "testb %%al,%%al\n\t" | ||
287 | "je 7f\n\t" | ||
288 | "movl %4,%%edi\n\t" | ||
289 | "movl %%edx,%%ecx\n\t" | ||
290 | "repne\n\t" | ||
291 | "scasb\n\t" | ||
292 | "je 2b\n\t" | ||
293 | "decl %1\n\t" | ||
294 | "cmpb $0,(%1)\n\t" | ||
295 | "je 7f\n\t" | ||
296 | "movl %1,%0\n" | ||
297 | "3:\tlodsb\n\t" | ||
298 | "testb %%al,%%al\n\t" | ||
299 | "je 5f\n\t" | ||
300 | "movl %4,%%edi\n\t" | ||
301 | "movl %%edx,%%ecx\n\t" | ||
302 | "repne\n\t" | ||
303 | "scasb\n\t" | ||
304 | "jne 3b\n\t" | ||
305 | "decl %1\n\t" | ||
306 | "cmpb $0,(%1)\n\t" | ||
307 | "je 5f\n\t" | ||
308 | "movb $0,(%1)\n\t" | ||
309 | "incl %1\n\t" | ||
310 | "jmp 6f\n" | ||
311 | "5:\txorl %1,%1\n" | ||
312 | "6:\tcmpb $0,(%0)\n\t" | ||
313 | "jne 7f\n\t" | ||
314 | "xorl %0,%0\n" | ||
315 | "7:\ttestl %0,%0\n\t" | ||
316 | "jne 8f\n\t" | ||
317 | "movl %0,%1\n" | ||
318 | "8:" | ||
319 | :"=b" (__res),"=S" (___strtok) | ||
320 | :"0" (___strtok),"1" (s),"g" (ct) | ||
321 | ); | ||
322 | return __res; | ||
323 | } | ||
324 | |||
325 | inline void * memcpy(void * dest,const void * src, int n) | ||
326 | { | ||
327 | __asm__ ("cld\n\t" | ||
328 | "rep\n\t" | ||
329 | "movsb" | ||
330 | ::"c" (n),"S" (src),"D" (dest) | ||
331 | ); | ||
332 | return dest; | ||
333 | } | ||
334 | |||
335 | inline void * memmove(void * dest,const void * src, int n) | ||
336 | { | ||
337 | if (dest<src) | ||
338 | __asm__("cld\n\t" | ||
339 | "rep\n\t" | ||
340 | "movsb" | ||
341 | ::"c" (n),"S" (src),"D" (dest) | ||
342 | ); | ||
343 | else | ||
344 | __asm__("std\n\t" | ||
345 | "rep\n\t" | ||
346 | "movsb" | ||
347 | ::"c" (n),"S" (src+n-1),"D" (dest+n-1) | ||
348 | ); | ||
349 | return dest; | ||
350 | } | ||
351 | |||
352 | static inline int memcmp(const void * cs,const void * ct,int count) | ||
353 | { | ||
354 | register int __res ; | ||
355 | __asm__("cld\n\t" | ||
356 | "repe\n\t" | ||
357 | "cmpsb\n\t" | ||
358 | "je 1f\n\t" | ||
359 | "movl $1,%%eax\n\t" | ||
360 | "jl 1f\n\t" | ||
361 | "negl %%eax\n" | ||
362 | "1:" | ||
363 | :"=a" (__res):"0" (0),"D" (cs),"S" (ct),"c" (count) | ||
364 | ); | ||
365 | return __res; | ||
366 | } | ||
367 | |||
368 | inline void * memchr(const void * cs,char c,int count) | ||
369 | { | ||
370 | register void * __res ; | ||
371 | if (!count) | ||
372 | return NULL; | ||
373 | __asm__("cld\n\t" | ||
374 | "repne\n\t" | ||
375 | "scasb\n\t" | ||
376 | "je 1f\n\t" | ||
377 | "movl $1,%0\n" | ||
378 | "1:\tdecl %0" | ||
379 | :"=D" (__res):"a" (c),"D" (cs),"c" (count) | ||
380 | ); | ||
381 | return __res; | ||
382 | } | ||
383 | |||
384 | static inline void * memset(void * s,char c,int count) | ||
385 | { | ||
386 | __asm__("cld\n\t" | ||
387 | "rep\n\t" | ||
388 | "stosb" | ||
389 | ::"a" (c),"D" (s),"c" (count) | ||
390 | ); | ||
391 | return s; | ||
392 | } \ No newline at end of file | ||
diff --git a/src/lib/wait.c b/src/lib/wait.c new file mode 100644 index 0000000..2815c16 --- /dev/null +++ b/src/lib/wait.c | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * linux/lib/wait.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | #include <sys/wait.h> | ||
10 | |||
11 | _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) | ||
12 | |||
13 | pid_t wait(int * wait_stat) | ||
14 | { | ||
15 | return waitpid(-1,wait_stat,0); | ||
16 | } | ||
diff --git a/src/lib/write.c b/src/lib/write.c new file mode 100644 index 0000000..df52e74 --- /dev/null +++ b/src/lib/write.c | |||
@@ -0,0 +1,10 @@ | |||
1 | /* | ||
2 | * linux/lib/write.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | #define __LIBRARY__ | ||
8 | #include <unistd.h> | ||
9 | |||
10 | _syscall3(int,write,int,fd,const char *,buf,off_t,count) | ||
diff --git a/src/mm/Makefile b/src/mm/Makefile new file mode 100644 index 0000000..98913c4 --- /dev/null +++ b/src/mm/Makefile | |||
@@ -0,0 +1,37 @@ | |||
1 | |||
2 | include ../Makefile.header | ||
3 | |||
4 | LDFLAGS += -r | ||
5 | CFLAGS += -I../include | ||
6 | CPP += -I../include | ||
7 | |||
8 | .c.o: | ||
9 | @$(CC) $(CFLAGS) \ | ||
10 | -c -o $*.o $< | ||
11 | .s.o: | ||
12 | @$(AS) -o $*.o $< | ||
13 | .c.s: | ||
14 | @$(CC) $(CFLAGS) \ | ||
15 | -S -o $*.s $< | ||
16 | |||
17 | OBJS = memory.o page.o | ||
18 | |||
19 | all: mm.o | ||
20 | |||
21 | mm.o: $(OBJS) | ||
22 | @$(LD) $(LDFLAGS) -o mm.o $(OBJS) | ||
23 | |||
24 | clean: | ||
25 | @rm -f core *.o *.a tmp_make | ||
26 | @for i in *.c;do rm -f `basename $$i .c`.s;done | ||
27 | |||
28 | dep: | ||
29 | @sed '/\#\#\# Dependencies/q' < Makefile > tmp_make | ||
30 | @(for i in *.c;do $(CPP) -M $$i;done) >> tmp_make | ||
31 | @cp tmp_make Makefile | ||
32 | |||
33 | ### Dependencies: | ||
34 | memory.o: memory.c ../include/signal.h ../include/sys/types.h \ | ||
35 | ../include/asm/system.h ../include/linux/sched.h \ | ||
36 | ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \ | ||
37 | ../include/linux/kernel.h | ||
diff --git a/src/mm/memory.c b/src/mm/memory.c new file mode 100644 index 0000000..340a7fc --- /dev/null +++ b/src/mm/memory.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * linux/mm/memory.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * demand-loading started 01.12.91 - seems it is high on the list of | ||
9 | * things wanted, and it should be easy to implement. - Linus | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * Ok, demand-loading was easy, shared pages a little bit tricker. Shared | ||
14 | * pages started 02.12.91, seems to work. - Linus. | ||
15 | * | ||
16 | * Tested sharing by executing about 30 /bin/sh: under the old kernel it | ||
17 | * would have taken more than the 6M I have free, but it worked well as | ||
18 | * far as I could see. | ||
19 | * | ||
20 | * Also corrected some "invalidate()"s - I wasn't doing enough of them. | ||
21 | */ | ||
22 | |||
23 | #include <signal.h> | ||
24 | |||
25 | #include <asm/system.h> | ||
26 | |||
27 | #include <linux/sched.h> | ||
28 | #include <linux/head.h> | ||
29 | #include <linux/kernel.h> | ||
30 | |||
31 | void do_exit(long code); | ||
32 | |||
33 | static inline void oom(void) | ||
34 | { | ||
35 | printk("out of memory\n\r"); | ||
36 | do_exit(SIGSEGV); | ||
37 | } | ||
38 | |||
39 | #define invalidate() \ | ||
40 | __asm__("movl %%eax,%%cr3"::"a" (0)) | ||
41 | |||
42 | /* these are not to be changed without changing head.s etc */ | ||
43 | #define LOW_MEM 0x100000 | ||
44 | #define PAGING_MEMORY (15*1024*1024) | ||
45 | #define PAGING_PAGES (PAGING_MEMORY>>12) | ||
46 | #define MAP_NR(addr) (((addr)-LOW_MEM)>>12) | ||
47 | #define USED 100 | ||
48 | |||
49 | #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ | ||
50 | current->start_code + current->end_code) | ||
51 | |||
52 | static long HIGH_MEMORY = 0; | ||
53 | |||
54 | #define copy_page(from,to) \ | ||
55 | __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024)) | ||
56 | |||
57 | static unsigned char mem_map [ PAGING_PAGES ] = {0,}; | ||
58 | |||
59 | /* | ||
60 | * Get physical address of first (actually last :-) free page, and mark it | ||
61 | * used. If no free pages left, return 0. | ||
62 | */ | ||
63 | unsigned long get_free_page(void) | ||
64 | { | ||
65 | register unsigned long __res asm("ax"); | ||
66 | |||
67 | __asm__("std ; repne ; scasb\n\t" | ||
68 | "jne 1f\n\t" | ||
69 | "movb $1,1(%%edi)\n\t" | ||
70 | "sall $12,%%ecx\n\t" | ||
71 | "addl %2,%%ecx\n\t" | ||
72 | "movl %%ecx,%%edx\n\t" | ||
73 | "movl $1024,%%ecx\n\t" | ||
74 | "leal 4092(%%edx),%%edi\n\t" | ||
75 | "rep ; stosl\n\t" | ||
76 | " movl %%edx,%%eax\n" | ||
77 | "1: cld" | ||
78 | :"=a" (__res) | ||
79 | :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), | ||
80 | "D" (mem_map+PAGING_PAGES-1) | ||
81 | ); | ||
82 | return __res; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Free a page of memory at physical address 'addr'. Used by | ||
87 | * 'free_page_tables()' | ||
88 | */ | ||
89 | void free_page(unsigned long addr) | ||
90 | { | ||
91 | if (addr < LOW_MEM) return; | ||
92 | if (addr >= HIGH_MEMORY) | ||
93 | panic("trying to free nonexistent page"); | ||
94 | addr -= LOW_MEM; | ||
95 | addr >>= 12; | ||
96 | if (mem_map[addr]--) return; | ||
97 | mem_map[addr]=0; | ||
98 | panic("trying to free free page"); | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * This function frees a continuos block of page tables, as needed | ||
103 | * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks. | ||
104 | */ | ||
105 | int free_page_tables(unsigned long from,unsigned long size) | ||
106 | { | ||
107 | unsigned long *pg_table; | ||
108 | unsigned long * dir, nr; | ||
109 | |||
110 | if (from & 0x3fffff) | ||
111 | panic("free_page_tables called with wrong alignment"); | ||
112 | if (!from) | ||
113 | panic("Trying to free up swapper memory space"); | ||
114 | size = (size + 0x3fffff) >> 22; | ||
115 | dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */ | ||
116 | for ( ; size-->0 ; dir++) { | ||
117 | if (!(1 & *dir)) | ||
118 | continue; | ||
119 | pg_table = (unsigned long *) (0xfffff000 & *dir); | ||
120 | for (nr=0 ; nr<1024 ; nr++) { | ||
121 | if (1 & *pg_table) | ||
122 | free_page(0xfffff000 & *pg_table); | ||
123 | *pg_table = 0; | ||
124 | pg_table++; | ||
125 | } | ||
126 | free_page(0xfffff000 & *dir); | ||
127 | *dir = 0; | ||
128 | } | ||
129 | invalidate(); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Well, here is one of the most complicated functions in mm. It | ||
135 | * copies a range of linerar addresses by copying only the pages. | ||
136 | * Let's hope this is bug-free, 'cause this one I don't want to debug :-) | ||
137 | * | ||
138 | * Note! We don't copy just any chunks of memory - addresses have to | ||
139 | * be divisible by 4Mb (one page-directory entry), as this makes the | ||
140 | * function easier. It's used only by fork anyway. | ||
141 | * | ||
142 | * NOTE 2!! When from==0 we are copying kernel space for the first | ||
143 | * fork(). Then we DONT want to copy a full page-directory entry, as | ||
144 | * that would lead to some serious memory waste - we just copy the | ||
145 | * first 160 pages - 640kB. Even that is more than we need, but it | ||
146 | * doesn't take any more memory - we don't copy-on-write in the low | ||
147 | * 1 Mb-range, so the pages can be shared with the kernel. Thus the | ||
148 | * special case for nr=xxxx. | ||
149 | */ | ||
150 | int copy_page_tables(unsigned long from,unsigned long to,long size) | ||
151 | { | ||
152 | unsigned long * from_page_table; | ||
153 | unsigned long * to_page_table; | ||
154 | unsigned long this_page; | ||
155 | unsigned long * from_dir, * to_dir; | ||
156 | unsigned long nr; | ||
157 | |||
158 | if ((from&0x3fffff) || (to&0x3fffff)) | ||
159 | panic("copy_page_tables called with wrong alignment"); | ||
160 | from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */ | ||
161 | to_dir = (unsigned long *) ((to>>20) & 0xffc); | ||
162 | size = ((unsigned) (size+0x3fffff)) >> 22; | ||
163 | for( ; size-->0 ; from_dir++,to_dir++) { | ||
164 | if (1 & *to_dir) | ||
165 | panic("copy_page_tables: already exist"); | ||
166 | if (!(1 & *from_dir)) | ||
167 | continue; | ||
168 | from_page_table = (unsigned long *) (0xfffff000 & *from_dir); | ||
169 | if (!(to_page_table = (unsigned long *) get_free_page())) | ||
170 | return -1; /* Out of memory, see freeing */ | ||
171 | *to_dir = ((unsigned long) to_page_table) | 7; | ||
172 | nr = (from==0)?0xA0:1024; | ||
173 | for ( ; nr-- > 0 ; from_page_table++,to_page_table++) { | ||
174 | this_page = *from_page_table; | ||
175 | if (!(1 & this_page)) | ||
176 | continue; | ||
177 | this_page &= ~2; | ||
178 | *to_page_table = this_page; | ||
179 | if (this_page > LOW_MEM) { | ||
180 | *from_page_table = this_page; | ||
181 | this_page -= LOW_MEM; | ||
182 | this_page >>= 12; | ||
183 | mem_map[this_page]++; | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | invalidate(); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * This function puts a page in memory at the wanted address. | ||
193 | * It returns the physical address of the page gotten, 0 if | ||
194 | * out of memory (either when trying to access page-table or | ||
195 | * page.) | ||
196 | */ | ||
197 | unsigned long put_page(unsigned long page,unsigned long address) | ||
198 | { | ||
199 | unsigned long tmp, *page_table; | ||
200 | |||
201 | /* NOTE !!! This uses the fact that _pg_dir=0 */ | ||
202 | |||
203 | if (page < LOW_MEM || page >= HIGH_MEMORY) | ||
204 | printk("Trying to put page %p at %p\n",page,address); | ||
205 | if (mem_map[(page-LOW_MEM)>>12] != 1) | ||
206 | printk("mem_map disagrees with %p at %p\n",page,address); | ||
207 | page_table = (unsigned long *) ((address>>20) & 0xffc); | ||
208 | if ((*page_table)&1) | ||
209 | page_table = (unsigned long *) (0xfffff000 & *page_table); | ||
210 | else { | ||
211 | if (!(tmp=get_free_page())) | ||
212 | return 0; | ||
213 | *page_table = tmp|7; | ||
214 | page_table = (unsigned long *) tmp; | ||
215 | } | ||
216 | page_table[(address>>12) & 0x3ff] = page | 7; | ||
217 | /* no need for invalidate */ | ||
218 | return page; | ||
219 | } | ||
220 | |||
221 | void un_wp_page(unsigned long * table_entry) | ||
222 | { | ||
223 | unsigned long old_page,new_page; | ||
224 | |||
225 | old_page = 0xfffff000 & *table_entry; | ||
226 | if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { | ||
227 | *table_entry |= 2; | ||
228 | invalidate(); | ||
229 | return; | ||
230 | } | ||
231 | if (!(new_page=get_free_page())) | ||
232 | oom(); | ||
233 | if (old_page >= LOW_MEM) | ||
234 | mem_map[MAP_NR(old_page)]--; | ||
235 | *table_entry = new_page | 7; | ||
236 | invalidate(); | ||
237 | copy_page(old_page,new_page); | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * This routine handles present pages, when users try to write | ||
242 | * to a shared page. It is done by copying the page to a new address | ||
243 | * and decrementing the shared-page counter for the old page. | ||
244 | * | ||
245 | * If it's in code space we exit with a segment error. | ||
246 | */ | ||
247 | void do_wp_page(unsigned long error_code,unsigned long address) | ||
248 | { | ||
249 | #if 0 | ||
250 | /* we cannot do this yet: the estdio library writes to code space */ | ||
251 | /* stupid, stupid. I really want the libc.a from GNU */ | ||
252 | if (CODE_SPACE(address)) | ||
253 | do_exit(SIGSEGV); | ||
254 | #endif | ||
255 | un_wp_page((unsigned long *) | ||
256 | (((address>>10) & 0xffc) + (0xfffff000 & | ||
257 | *((unsigned long *) ((address>>20) &0xffc))))); | ||
258 | |||
259 | } | ||
260 | |||
261 | void write_verify(unsigned long address) | ||
262 | { | ||
263 | unsigned long page; | ||
264 | |||
265 | if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1)) | ||
266 | return; | ||
267 | page &= 0xfffff000; | ||
268 | page += ((address>>10) & 0xffc); | ||
269 | if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */ | ||
270 | un_wp_page((unsigned long *) page); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | void get_empty_page(unsigned long address) | ||
275 | { | ||
276 | unsigned long tmp; | ||
277 | |||
278 | if (!(tmp=get_free_page()) || !put_page(tmp,address)) { | ||
279 | free_page(tmp); /* 0 is ok - ignored */ | ||
280 | oom(); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * try_to_share() checks the page at address "address" in the task "p", | ||
286 | * to see if it exists, and if it is clean. If so, share it with the current | ||
287 | * task. | ||
288 | * | ||
289 | * NOTE! This assumes we have checked that p != current, and that they | ||
290 | * share the same executable. | ||
291 | */ | ||
292 | static int try_to_share(unsigned long address, struct task_struct * p) | ||
293 | { | ||
294 | unsigned long from; | ||
295 | unsigned long to; | ||
296 | unsigned long from_page; | ||
297 | unsigned long to_page; | ||
298 | unsigned long phys_addr; | ||
299 | |||
300 | from_page = to_page = ((address>>20) & 0xffc); | ||
301 | from_page += ((p->start_code>>20) & 0xffc); | ||
302 | to_page += ((current->start_code>>20) & 0xffc); | ||
303 | /* is there a page-directory at from? */ | ||
304 | from = *(unsigned long *) from_page; | ||
305 | if (!(from & 1)) | ||
306 | return 0; | ||
307 | from &= 0xfffff000; | ||
308 | from_page = from + ((address>>10) & 0xffc); | ||
309 | phys_addr = *(unsigned long *) from_page; | ||
310 | /* is the page clean and present? */ | ||
311 | if ((phys_addr & 0x41) != 0x01) | ||
312 | return 0; | ||
313 | phys_addr &= 0xfffff000; | ||
314 | if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM) | ||
315 | return 0; | ||
316 | to = *(unsigned long *) to_page; | ||
317 | if (!(to & 1)) { | ||
318 | if ((to = get_free_page())) | ||
319 | *(unsigned long *) to_page = to | 7; | ||
320 | else | ||
321 | oom(); | ||
322 | } | ||
323 | to &= 0xfffff000; | ||
324 | to_page = to + ((address>>10) & 0xffc); | ||
325 | if (1 & *(unsigned long *) to_page) | ||
326 | panic("try_to_share: to_page already exists"); | ||
327 | /* share them: write-protect */ | ||
328 | *(unsigned long *) from_page &= ~2; | ||
329 | *(unsigned long *) to_page = *(unsigned long *) from_page; | ||
330 | invalidate(); | ||
331 | phys_addr -= LOW_MEM; | ||
332 | phys_addr >>= 12; | ||
333 | mem_map[phys_addr]++; | ||
334 | return 1; | ||
335 | } | ||
336 | |||
337 | /* | ||
338 | * share_page() tries to find a process that could share a page with | ||
339 | * the current one. Address is the address of the wanted page relative | ||
340 | * to the current data space. | ||
341 | * | ||
342 | * We first check if it is at all feasible by checking executable->i_count. | ||
343 | * It should be >1 if there are other tasks sharing this inode. | ||
344 | */ | ||
345 | static int share_page(unsigned long address) | ||
346 | { | ||
347 | struct task_struct ** p; | ||
348 | |||
349 | if (!current->executable) | ||
350 | return 0; | ||
351 | if (current->executable->i_count < 2) | ||
352 | return 0; | ||
353 | for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { | ||
354 | if (!*p) | ||
355 | continue; | ||
356 | if (current == *p) | ||
357 | continue; | ||
358 | if ((*p)->executable != current->executable) | ||
359 | continue; | ||
360 | if (try_to_share(address,*p)) | ||
361 | return 1; | ||
362 | } | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | void do_no_page(unsigned long error_code,unsigned long address) | ||
367 | { | ||
368 | int nr[4]; | ||
369 | unsigned long tmp; | ||
370 | unsigned long page; | ||
371 | int block,i; | ||
372 | |||
373 | address &= 0xfffff000; | ||
374 | tmp = address - current->start_code; | ||
375 | if (!current->executable || tmp >= current->end_data) { | ||
376 | get_empty_page(address); | ||
377 | return; | ||
378 | } | ||
379 | if (share_page(tmp)) | ||
380 | return; | ||
381 | if (!(page = get_free_page())) | ||
382 | oom(); | ||
383 | /* remember that 1 block is used for header */ | ||
384 | block = 1 + tmp/BLOCK_SIZE; | ||
385 | for (i=0 ; i<4 ; block++,i++) | ||
386 | nr[i] = bmap(current->executable,block); | ||
387 | bread_page(page,current->executable->i_dev,nr); | ||
388 | i = tmp + 4096 - current->end_data; | ||
389 | tmp = page + 4096; | ||
390 | while (i-- > 0) { | ||
391 | tmp--; | ||
392 | *(char *)tmp = 0; | ||
393 | } | ||
394 | if (put_page(page,address)) | ||
395 | return; | ||
396 | free_page(page); | ||
397 | oom(); | ||
398 | } | ||
399 | |||
400 | void mem_init(long start_mem, long end_mem) | ||
401 | { | ||
402 | int i; | ||
403 | |||
404 | HIGH_MEMORY = end_mem; | ||
405 | for (i=0 ; i<PAGING_PAGES ; i++) | ||
406 | mem_map[i] = USED; | ||
407 | i = MAP_NR(start_mem); | ||
408 | end_mem -= start_mem; | ||
409 | end_mem >>= 12; | ||
410 | while (end_mem-->0) | ||
411 | mem_map[i++]=0; | ||
412 | } | ||
413 | |||
414 | void calc_mem(void) | ||
415 | { | ||
416 | int i,j,k,free=0; | ||
417 | long * pg_tbl; | ||
418 | |||
419 | for(i=0 ; i<PAGING_PAGES ; i++) | ||
420 | if (!mem_map[i]) free++; | ||
421 | printk("%d pages free (of %d)\n\r",free,PAGING_PAGES); | ||
422 | for(i=2 ; i<1024 ; i++) { | ||
423 | if (1&pg_dir[i]) { | ||
424 | pg_tbl=(long *) (0xfffff000 & pg_dir[i]); | ||
425 | for(j=k=0 ; j<1024 ; j++) | ||
426 | if (pg_tbl[j]&1) | ||
427 | k++; | ||
428 | printk("Pg-dir[%d] uses %d pages\n",i,k); | ||
429 | } | ||
430 | } | ||
431 | } | ||
diff --git a/src/mm/page.s b/src/mm/page.s new file mode 100644 index 0000000..9ebf3f7 --- /dev/null +++ b/src/mm/page.s | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * linux/mm/page.s | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * page.s contains the low-level page-exception code. | ||
9 | * the real work is done in mm.c | ||
10 | */ | ||
11 | |||
12 | .globl page_fault | ||
13 | |||
14 | page_fault: | ||
15 | xchgl %eax,(%esp) | ||
16 | pushl %ecx | ||
17 | pushl %edx | ||
18 | push %ds | ||
19 | push %es | ||
20 | push %fs | ||
21 | movl $0x10,%edx | ||
22 | mov %dx,%ds | ||
23 | mov %dx,%es | ||
24 | mov %dx,%fs | ||
25 | movl %cr2,%edx | ||
26 | pushl %edx | ||
27 | pushl %eax | ||
28 | testl $1,%eax | ||
29 | jne 1f | ||
30 | call do_no_page | ||
31 | jmp 2f | ||
32 | 1: call do_wp_page | ||
33 | 2: addl $8,%esp | ||
34 | pop %fs | ||
35 | pop %es | ||
36 | pop %ds | ||
37 | popl %edx | ||
38 | popl %ecx | ||
39 | popl %eax | ||
40 | iret | ||
diff --git a/src/tools/build.sh b/src/tools/build.sh new file mode 100755 index 0000000..d542a8f --- /dev/null +++ b/src/tools/build.sh | |||
@@ -0,0 +1,40 @@ | |||
1 | #!/bin/bash | ||
2 | # build.sh -- a shell version of build.c for the new bootsect.s & setup.s | ||
3 | # author: falcon <wuzhangjin@gmail.com> | ||
4 | # update: 2008-10-10 | ||
5 | |||
6 | bootsect=$1 | ||
7 | setup=$2 | ||
8 | system=$3 | ||
9 | IMAGE=$4 | ||
10 | root_dev=$5 | ||
11 | |||
12 | # Set the biggest sys_size | ||
13 | # Changes from 0x20000 to 0x30000 by tigercn to avoid oversized code. | ||
14 | SYS_SIZE=$((0x3000*16)) | ||
15 | |||
16 | # set the default "device" file for root image file | ||
17 | if [ -z "$root_dev" ]; then | ||
18 | DEFAULT_MAJOR_ROOT=3 | ||
19 | DEFAULT_MINOR_ROOT=1 | ||
20 | else | ||
21 | DEFAULT_MAJOR_ROOT=${root_dev:0:2} | ||
22 | DEFAULT_MINOR_ROOT=${root_dev:2:3} | ||
23 | fi | ||
24 | |||
25 | # Write bootsect (512 bytes, one sector) to stdout | ||
26 | [ ! -f "$bootsect" ] && echo "there is no bootsect binary file there" && exit -1 | ||
27 | dd if=$bootsect bs=512 count=1 of=$IMAGE 2>&1 >/dev/null | ||
28 | |||
29 | # Write setup(4 * 512bytes, four sectors) to stdout | ||
30 | [ ! -f "$setup" ] && echo "there is no setup binary file there" && exit -1 | ||
31 | dd if=$setup seek=1 bs=512 count=4 of=$IMAGE 2>&1 >/dev/null | ||
32 | |||
33 | # Write system(< SYS_SIZE) to stdout | ||
34 | [ ! -f "$system" ] && echo "there is no system binary file there" && exit -1 | ||
35 | system_size=`wc -c $system |cut -d" " -f1` | ||
36 | [ $system_size -gt $SYS_SIZE ] && echo "the system binary is too big" && exit -1 | ||
37 | dd if=$system seek=5 bs=512 count=$((2888-1-4)) of=$IMAGE 2>&1 >/dev/null | ||
38 | |||
39 | # Set "device" for the root image file | ||
40 | echo -ne "\x$DEFAULT_MINOR_ROOT\x$DEFAULT_MAJOR_ROOT" | dd ibs=1 obs=1 count=2 seek=508 of=$IMAGE conv=notrunc 2>&1 >/dev/null | ||