Subversion Repositories Spectranet

[/] [branches/] [gnubinutils/] [rom/] [tnfs_core.asm] - Blame information for rev 384

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 215 winston
;The MIT License
2
;
3
;Copyright (c) 2009 Dylan Smith
4
;
5
;Permission is hereby granted, free of charge, to any person obtaining a copy
6
;of this software and associated documentation files (the "Software"), to deal
7
;in the Software without restriction, including without limitation the rights
8
;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
;copies of the Software, and to permit persons to whom the Software is
10
;furnished to do so, subject to the following conditions:
11
;
12
;The above copyright notice and this permission notice shall be included in
13
;all copies or substantial portions of the Software.
14
;
15
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
;THE SOFTWARE.
22 381 winston
.include        "tnfs_defs.inc"
23
.include        "tnfs_sysvars.inc"
24
.include        "spectranet.inc"
25
.include        "sysvars.inc"
26
.include        "fcntl.inc"
27 384 winston
.include        "sockdefs.inc"
28 215 winston
 
29
; General TNFS core utility functions.
30
;------------------------------------------------------------------------
31
; F_tnfs_strcpy
32
; Copy a null terminated string in HL to the buffer in DE, up to B bytes long
33
; Returns with DE set to the buffer end + 1
34 381 winston
.text
35
.globl F_tnfs_strcpy
36
F_tnfs_strcpy:
37
.loop1:
38 215 winston
        ld a, (hl)
39
        ld (de), a
40
        inc de
41
        and a                   ; NULL terminator?
42
        ret z
43
        inc hl
44 381 winston
        djnz .loop1
45 215 winston
        xor a                   ; if we exhaust the maximum length,
46
        ld (de), a              ; make sure there's a NULL on the end.
47
        inc de
48
        ret
49
 
50
;------------------------------------------------------------------------
51
; F_tnfs_strcat
52
; Concatenates two null terminated strings.
53
; Arguments             HL = pointer to first string buffer
54
;                       DE = pointer to string to concatenate
55
;                       BC = buffer size in bytes
56
; On return, carry is set if the buffer was too small
57 381 winston
.globl F_tnfs_strcat
58
F_tnfs_strcat:
59 215 winston
        ; find the end of the first string
60
        dec bc                  ; guarantee that we can null terminate it
61 381 winston
.findend2:
62 215 winston
        ld a, (hl)
63
        and a
64 381 winston
        jr z, .string_end2
65 215 winston
        inc hl
66
        dec bc
67
        ld a, b
68
        or c
69 381 winston
        jr nz, .findend2
70 215 winston
        scf                     ; buffer too short
71
        ret
72 381 winston
.string_end2:
73 215 winston
        ld a, (de)              ; second string
74
        ld (hl), a
75
        and a                   ; null?
76
        ret z
77
        inc hl
78
        inc de
79
        dec bc
80
        ld a, b
81
        or c
82 381 winston
        jr nz, .string_end2
83 215 winston
        ld (hl), 0              ; add a terminator
84
        scf                     ; buffer too small
85
        ret
86
 
87
;------------------------------------------------------------------------
88
; F_tnfs_abspath
89
; Make an absolute path from a supplied relative path.
90
; Parameters    HL = pointer to path string
91
;               DE = pointer to a buffer to store the resulting path
92 234 winston
; In use mountpoint must be in v_curmountpt
93 215 winston
; On return DE points to the end of the new string.
94 381 winston
.globl F_tnfs_abspath
95
F_tnfs_abspath:
96 230 winston
        ld a, (hl)
97
        and a                   ; Empty string?
98 381 winston
        jr z, .donothing3       ; Do nothing.
99 230 winston
        cp '/'                  ; Absolute path?
100 215 winston
        ld b, 255
101
        jp z, F_tnfs_strcpy     ; yes, so just copy it verbatim.
102
 
103
        push hl
104
        ld (v_desave), de       ; save start of buffer
105 234 winston
        ld a, (v_curmountpt)    ; get the mount point we're working on
106 381 winston
        add a, v_cwd0 / 256     ; calculate the MSB
107 234 winston
        ld h, a
108
        ld l, 0                 ; set HL to the cwd
109 381 winston
.cploop3:
110 215 winston
        ld a, (hl)
111
        and a                   ; zero?
112 381 winston
        jr z, .stringend3
113 215 winston
        ld (de), a
114
        inc hl
115
        inc de
116 381 winston
        djnz .cploop3
117
.stringend3:
118 215 winston
        ld a, 255               ; did we actually copy anything?
119
        cp b
120 381 winston
        jr z, .addslash3                ; no, so put on a leading /
121 215 winston
        dec de
122
        ld a, (de)              ; check for trailing /
123
        cp '/'
124
        inc de
125 381 winston
        jr z, .parsepath3       ; trailing / is present, nothing to do
126
.addslash3:
127 215 winston
        ld a, '/'
128
        ld (de), a              ; add the trailing /
129
        inc de
130 381 winston
.parsepath3:
131 215 winston
        pop hl
132
 
133
        ; Build up the actual path. If we encounter a ../, remove the
134
        ; top path entry. If we encounter a ./, skip it.
135 381 winston
.loop3:
136 215 winston
        ld a, (hl)              ; check for end of string
137
        and a
138 381 winston
        jr z, .addnull3         ; finished so add a null to the destination
139
        call .relativepath3     ; check for relative path ../ or ./
140
        jr c, .loop3            ; relative path processed, don't copy any more
141
.copypath3:
142 215 winston
        ld a, (hl)              ; copy the byte
143
        ld (de), a
144
        inc hl
145
        inc de
146
        cp '/'                  ; up to a /
147 381 winston
        jr z, .loop3            ; when we go for the next bit.
148 215 winston
        and a                   ; hit the NULL at the end?
149
        ret z                   ; all done
150 381 winston
        jr .copypath3
151 215 winston
 
152 381 winston
.donothing3:                    ; simply advance DE to the end of
153 230 winston
        ld a, (de)              ; the current path string
154
        and a
155
        ret z
156
        inc de
157 381 winston
        jr .donothing3
158 230 winston
 
159 381 winston
.addnull3:
160 215 winston
        xor a
161
        ld (de), a
162
        inc de
163
        ret
164
 
165
        ; Deal with relative paths. When a ../ is encountered, the last
166
        ; dir should be removed (stopping at the start of the string).
167
        ; If a ./ is encountered it should be skipped.
168 381 winston
.relativepath3:
169 215 winston
        ld (v_hlsave), hl       ; save pointer
170
        ld a, (hl)
171
        cp '.'
172 381 winston
        jr nz, .notrelative3    ; definitely not a relative path
173 215 winston
        inc hl
174
        ld a, (hl)
175
        cp '/'
176 381 winston
        jr z, .omit3            ; It's a ./ - omit it
177 215 winston
        and a                   ; or a . (null), same thing
178 381 winston
        jr z, .omitnull3
179 215 winston
        cp '.'
180 381 winston
        jr nz, .notrelative3    ; It's .somethingelse3
181 215 winston
        inc hl
182
        ld a, (hl)
183
        cp '/'
184 381 winston
        jr z, .relative3                ; relative path
185 215 winston
        and 0                   ; null terminator? also relative path
186 381 winston
        jr z, .relativenull3    ;
187
        jr .notrelative3                ; something else
188
.relative3:
189 215 winston
        inc hl                  ; make HL point at next byte for return.
190 381 winston
.relativenull3:
191 215 winston
        ex de, hl               ; do the work in HL
192
        push hl                 ; save the pointer.
193
        ld bc, (v_desave)       ; get the pointer to the start of the buffer
194
        inc bc                  ; add 1 to it
195
        sbc hl, bc              ; compare with the current address
196
        pop hl                  ; get current address back into HL
197 381 winston
        jr z, .relativedone3    ; at the root already, so do nothing
198 215 winston
 
199
        dec hl                  ; get rid of the topmost path element
200
        ld (hl), 0              ; remove the trailing /
201 381 winston
.chewpath3:
202 215 winston
        dec hl
203
        ld a, (hl)              ; is it a / ?
204
        cp '/'                  ; if so we're nearly done
205 381 winston
        jr z, .relativealmostdone3
206 215 winston
        ld (hl), 0              ; erase char
207 381 winston
        jr .chewpath3
208
.relativealmostdone3:
209 215 winston
        inc hl                  ; HL points at next char
210 381 winston
.relativedone3:
211 215 winston
        ex de, hl
212
        scf                     ; indicate that path copy shouldn't take place
213
        ret
214
 
215 381 winston
.notrelative3:
216 215 winston
        ld hl, (v_hlsave)
217
        and a                   ; set Z flag if zero
218
        ret
219 381 winston
.omit3:
220 215 winston
        inc hl                  ; advance pointer to next element of the path
221 381 winston
.omitnull3:
222 215 winston
        scf                     ; set carry
223
        ret
224
 
225
;------------------------------------------------------------------------
226
; F_tnfs_header_w
227 216 winston
; Creates a TNFS header at a fixed address, buf_tnfs_wkspc, with the
228 215 winston
; extant session id
229 381 winston
.globl F_tnfs_header_w
230
F_tnfs_header_w:
231 234 winston
        push af
232
        ld a, (v_curmountpt)    ; find the SID for this mount point
233
        rlca                    ; mutiply by two
234 381 winston
        add a, v_tnfs_sid0 % 256        ; and add the offset
235 234 winston
        ld h, v_tnfs_sid0 / 256 ; set HL = pointer to SID
236
        ld l, a
237
        ld e, (hl)              ; set DE to the SID
238
        inc l
239
        ld d, (hl)
240 216 winston
        ld hl, buf_tnfs_wkspc
241 234 winston
        pop af
242 215 winston
; F_tnfs_header
243
; Creates a TNFS header. Session ID in DE. Command in A. HL is a pointer
244
; to the buffer to fill.
245
; HL points to the end of the header on exit.
246 381 winston
.globl F_tnfs_header
247
F_tnfs_header:
248 215 winston
        ld (hl), e
249
        inc hl
250
        ld (hl), d
251
        inc hl
252
        push af
253 234 winston
        ld a, (v_curmountpt)    ; calculate the sequence number storage
254 381 winston
        add a, v_tnfs_seqno0 % 256
255 234 winston
        ld e, a
256
        ld d, v_tnfs_seqno0 / 256
257
        ld a, (de)
258 215 winston
        inc a                   ; pre-increment the sequence number
259
        ld (hl), a
260 234 winston
        ld (de), a              ; so that the seqno in memory = current seq
261 215 winston
        pop af
262
        inc hl
263
        ld (hl), a              ; command
264
        inc hl
265
        ret
266
 
267
;------------------------------------------------------------------------
268 236 winston
; F_tnfs_prepsock
269
; Open the socket for TNFS datagrams if not already open, otherwise
270
; just set up the connection data for the datagrams.
271 215 winston
; Returns with carry set and A=error on error.
272
; HL=pointer to 4 byte IP address
273 381 winston
.globl F_tnfs_prepsock
274
F_tnfs_prepsock:
275 234 winston
        ld a, (v_curmountpt)    ; calculate the offset to the socket info
276
        rlca                    ; multiply by 8
277
        rlca
278
        rlca
279 381 winston
        add a, v_tnfs_sockinfo0 % 256
280 234 winston
        ld e, a                 ; set DE to the address of the sockinfo
281
        ld d, v_tnfs_sockinfo0 / 256
282
 
283
        ldi                     ; copy the IP data into the
284
        ldi                     ; sockinfo structure.
285 215 winston
        ldi
286
        ldi
287 234 winston
        ex de, hl
288
        ld (hl), 0x00           ; dest port = 16384
289
        inc l
290
        ld (hl), 0x40
291
        inc l
292
        ld a, (v_curmountpt)
293
        ld (hl), a              ; LSB of source port = mount point
294
        inc l
295
        ld (hl), 0x78           ; MSB of source port
296 236 winston
 
297
        ld a, (v_tnfs_sock)
298
        and a                   ; if it's zero we need to open the socket
299
        ret nz                  ; socket is already open
300 234 winston
        ld c, SOCK_DGRAM        ; Request a datagram socket.
301 215 winston
        call SOCKET             ; open a UDP socket.
302
        ret c
303 234 winston
        ld (v_tnfs_sock), a
304 215 winston
        ret
305
 
306
;------------------------------------------------------------------------
307
; F_tnfs_message_w
308 216 winston
; Sends the block of data starting at buf_tnfs_wkspc and ending at DE.
309 381 winston
.globl F_tnfs_message_w
310
F_tnfs_message_w:
311 215 winston
        ex de, hl               ; end pointer into HL for length calc
312 381 winston
.globl F_tnfs_message_w_hl
313
F_tnfs_message_w_hl:            ; entry point for when HL is already set
314 216 winston
        ld de, buf_tnfs_wkspc   ; start of block
315 215 winston
        sbc hl, de              ; calculate length
316
        ld b, h
317
        ld c, l
318
;------------------------------------------------------------------------
319
; F_tnfs_message
320
; Sends the block of data pointed to by DE for BC bytes and gets the
321
; response.
322 381 winston
.globl F_tnfs_message
323
F_tnfs_message:
324 215 winston
        ld a, tnfs_max_retries  ; number of retries
325
        ld (v_tnfs_retriesleft), a      ; into memory
326 370 winston
        ld (v_tnfs_tx_de), de   ; save pointer
327
        ld (v_tnfs_tx_bc), bc   ; save size
328 215 winston
 
329 234 winston
        ld a, (v_curmountpt)    ; current mount point
330
        rlca                    ; multiply by 8 to find the sockinfo
331
        rlca
332
        rlca
333 381 winston
        add a, v_tnfs_sockinfo0 % 256   ; LSB
334 234 winston
        ld h, v_tnfs_sockinfo0 / 256    ; MSB
335
        ld l, a
336 370 winston
        ld (v_tnfs_tx_hl), hl   ; save sockinfo pointer
337 381 winston
.retryloop9:
338 370 winston
        ld hl, (v_tnfs_tx_hl)   ; Fetch parameters
339
        ld de, (v_tnfs_tx_de)
340
        ld bc, (v_tnfs_tx_bc)
341 234 winston
        ld a, (v_tnfs_sock)     ; socket descriptor
342 215 winston
        call SENDTO             ; send the data
343 381 winston
        jr nc, .pollstart9
344 370 winston
        ret                     ; error, leave now
345 215 winston
 
346
        ; wait for the response by polling
347 381 winston
.pollstart9:
348 215 winston
        call F_tnfs_poll
349 381 winston
        jr nc, .continue9       ; a message is ready
350 215 winston
        ld a, (v_tnfs_retriesleft) ; get retries left
351
        dec a                   ; decrement it
352
        ld (v_tnfs_retriesleft), a ; and store it
353
        and a                   ; is it at zero?
354 381 winston
        jr nz, .retryloop9
355
        ld a, TTIMEOUT          ; error code - we tried...but9 gave up
356 215 winston
        scf                     ; timed out
357
        ret
358
 
359 381 winston
.continue9:
360 370 winston
        ld ix, (v_tnfs_tx_de)   ; start of the block we sent
361 302 winston
        ld a, (ix+tnfs_cmd_offset)      ; check the command
362
        cp TNFS_OP_READ         ; and see if it's a read operation
363 234 winston
 
364
        ld hl, v_vfs_sockinfo   ; Address to receive remote datagram IP/port
365 215 winston
        ld de, tnfs_recv_buffer ; Address to receive data
366 302 winston
        ld a, (v_tnfs_sock)     ; The tnfs socket
367 381 winston
        jr z, .read9            ; ...if9 the command was READ, handle it
368 370 winston
 
369 215 winston
        ld bc, 1024             ; max message size
370
        call RECVFROM
371
        ld a, (tnfs_recv_buffer + tnfs_seqno_offset)
372 234 winston
 
373 215 winston
        push bc
374
        ld b, a
375 234 winston
        ld a, (v_curmountpt)    ; find the sequence number storage
376 381 winston
        add a, v_tnfs_seqno0 % 256
377 234 winston
        ld l, a
378
        ld h, v_tnfs_seqno0 / 256
379
        ld a, (hl)
380 215 winston
        cp b                    ; sequence number match? if not
381
        pop bc
382 381 winston
        jr nz, .pollstart9      ; see if the real message is still to come
383 215 winston
        ret
384
 
385 302 winston
        ; read is done in two phases - first get the header, then
386
        ; once we've got that copy the data directly to the required
387
        ; memory address instead of via the tnfs buffer.
388 381 winston
.read9:
389 302 winston
        ld bc, TNFS_READHEADERSZ ; just pull out the header
390
        call RECVFROM
391 312 winston
        ret c                   ; leave on error
392 302 winston
        ld a, (tnfs_recv_buffer + tnfs_seqno_offset)
393
        ld b, a
394
        ld a, (v_curmountpt)    ; find the sequence number storage
395 381 winston
        add a, v_tnfs_seqno0 % 256
396 302 winston
        ld l, a
397
        ld h, v_tnfs_seqno0 / 256
398 370 winston
        ld a, (hl)              ; Consume rest of packet when no match
399 302 winston
        cp b                    ; sequence number match? if not
400 381 winston
        jr nz, .consume9                ; consume and discard the non-match data
401 302 winston
 
402
        ; check for error conditions
403
        ld a, (tnfs_recv_buffer+tnfs_err_offset)
404
        and a
405 381 winston
        jr nz, .leaveread9
406 302 winston
 
407
        ld de, (v_read_destination)     ; get destination address
408
        push de
409
        ld bc, (tnfs_recv_buffer+tnfs_msg_offset)       ; length
410
        ld a, (v_tnfs_sock)
411
        call F_restorepage      ; restore original RAM
412
        call RECV               ; use recv, not recvfrom for the remains
413
        pop hl                  ; calculate the new value
414 312 winston
        push af
415
        call F_fetchpage        ; get our page back
416
        pop af
417 302 winston
        ret c                   ; exit on error
418
        add hl, bc              ; that DE should have on exit.
419
        ex de, hl
420
        or a                    ; ensure carry is reset
421
        ret
422 381 winston
.leaveread9:
423 311 winston
        scf                     ; indicate error
424
        ret
425 302 winston
 
426 381 winston
.consume9:                      ; consume and discard data we don't want
427 367 winston
        ld a, (v_tnfs_sock)     ; if there is any data to be consumed
428
        call POLLFD             ; (a non data datagram or an error datagram
429 381 winston
        jp z, .retryloop9       ; may not have any more data)
430 367 winston
 
431 370 winston
        ld de, tnfs_recv_buffer
432 367 winston
        ld bc, 256
433
        ld a, (v_tnfs_sock)
434
        call RECV               ; unload any remaining data from the socket
435 381 winston
        jr .consume9
436 367 winston
 
437 215 winston
;-------------------------------------------------------------------------
438
; F_tnfs_poll
439
; Polls the tnfs fd for 1 time unit. Returns with carry set if the time
440
; expired.
441 381 winston
.globl F_tnfs_poll
442
F_tnfs_poll:
443 367 winston
        ld a, (v_tnfs_backoff)
444
        and a
445 381 winston
        jr z, .setstart10
446 367 winston
        ld a, (v_tnfs_polltime)
447
        ld c, a
448
        rla                     ; multiply backoff time by 2
449 381 winston
        jr nc, .setsysvar10
450 367 winston
        ld a, c                 ; can't back off any more, restore value
451 381 winston
        jr .setb10
452
.setsysvar10:
453 367 winston
        ld (v_tnfs_polltime), a ; save new poll time
454 381 winston
.setb10:
455 367 winston
        ld b, a
456
        ei                      ; ensure interrupts are enabled
457 381 winston
.loop10:
458 215 winston
        push bc
459 234 winston
        ld a, (v_tnfs_sock)
460 215 winston
        call POLLFD
461
        pop bc
462 381 winston
        jr nz, .done10          ; data has arrived
463 367 winston
        halt                    ; timing: wait for next 50Hz interrupt
464 381 winston
        djnz .loop10
465 367 winston
        scf                     ; poll time has expired
466 215 winston
        ret
467 381 winston
.setstart10:
468 367 winston
        inc a
469
        ld (v_tnfs_backoff), a  ; set backoff flag
470
        ld a, tnfs_polltime     ; initial polltime
471
        ld (v_tnfs_polltime), a
472 381 winston
        jr .setb10
473
.done10:
474 367 winston
        xor a
475
        ld (v_tnfs_backoff), a  ; reset backoff flag
476
        ret
477 215 winston
 
478
;-------------------------------------------------------------------------
479
; F_tnfs_mounted
480
; Ask if a volume is mounted. Returns with carry reset if so, and
481
; carry set if not, with A set to the error number.
482 381 winston
.globl F_tnfs_mounted
483
F_tnfs_mounted:
484 234 winston
        ld a, (v_tnfs_sock)
485 215 winston
        and a
486
        ret nz                  ; valid handle exists, return
487
        scf                     ; no valid handle - set carry flag
488
        ld a, TNOTMOUNTED       ; No filesystem mounted
489
        ret
490
 
491
;----------------------------------------------------------------------------
492
; F_tnfs_pathcmd
493
; Many TNFS commands are just the command id + null terminated path.
494
; This routine handles the assembly of the data block for all of these.
495
; Arguments: A = command
496
;           HL = pointer to string argument
497 381 winston
.globl F_tnfs_pathcmd
498
F_tnfs_pathcmd:
499 215 winston
        push hl
500
        call F_tnfs_header_w    ; create the header in the workspace area
501
        ex de, hl               ; de now points at current address
502
        pop hl
503
        call F_tnfs_abspath     ; create absolute path
504
        call F_tnfs_message_w   ; send the message and get the reply.
505
        ret
506
 
507
; As above but handles the return code too.
508 234 winston
; A = current mount point
509
; B = command
510 381 winston
.globl F_tnfs_simplepathcmd
511
F_tnfs_simplepathcmd:
512 216 winston
        call F_fetchpage
513
        ret c
514 234 winston
        ld (v_curmountpt), a
515 286 winston
        ld a, b
516 215 winston
        call F_tnfs_pathcmd
517
; Entry point for simple exit handler
518 381 winston
.globl F_tnfs_simpleexit
519
F_tnfs_simpleexit:
520 216 winston
        jp c, F_leave
521 215 winston
        ld a, (tnfs_recv_buffer+tnfs_err_offset)
522
        and a
523 216 winston
        jp z, F_leave
524 215 winston
        scf
525 216 winston
        jp F_leave
526 215 winston
 
527 236 winston
;---------------------------------------------------------------------------
528
; F_tnfs_checkclose
529
; Checks to see if the socket should be closed, and if so, closes it.
530 381 winston
.globl F_tnfs_checkclose
531
F_tnfs_checkclose:
532 236 winston
        push hl
533
        push bc
534
        push af
535
        ld b,4
536
        ld hl, v_tnfs_sid0
537 381 winston
.loop15:
538 236 winston
        ld a, (hl)
539
        inc hl
540
        or (hl)
541 381 winston
        jr nz, .done15
542 236 winston
        inc hl
543 381 winston
        djnz .loop15
544 236 winston
 
545
        ; no SIDs were found, so the socket isn't needed; close it.
546
        ld a, (v_tnfs_sock)
547
        call CLOSE
548
        xor a
549
        ld (v_tnfs_sock), a             ; clear down the socket storage
550 381 winston
.done15:
551 236 winston
        pop af
552
        pop bc
553
        pop hl
554
        ret