about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--400.mu1
-rw-r--r--boot.subx89
-rw-r--r--shell/sandbox.mu3
3 files changed, 93 insertions, 0 deletions
diff --git a/400.mu b/400.mu
index 2f7896c8..2a0be7cf 100644
--- a/400.mu
+++ b/400.mu
@@ -10,6 +10,7 @@ sig read-key kbd: (addr keyboard) -> _/eax: byte
 
 # disk
 sig load-first-sector-from-primary-bus-secondary-drive out: (addr stream byte)
+sig store-first-sector-to-primary-bus-secondary-drive out: (addr stream byte)
 
 # tests
 sig count-test-failure
diff --git a/boot.subx b/boot.subx
index 200f201a..028862ad 100644
--- a/boot.subx
+++ b/boot.subx
@@ -971,6 +971,91 @@ $load-first-sector-from-primary-bus-secondary-drive:end:
   5d/pop-to-ebp
   c3/return
 
+store-first-sector-to-primary-bus-secondary-drive:  # in: (addr stream byte)
+  # . prologue
+  55/push-ebp
+  89/<- %ebp 4/r32/esp
+  # . save registers
+  50/push-eax
+  51/push-ecx
+  52/push-edx
+  53/push-ebx
+  # check for drive
+  (secondary-drive-exists?)  # => eax
+  3d/compare-eax-and 0/imm32/false
+  0f 84/jump-if-= $store-first-sector-to-primary-bus-secondary-drive:end/disp32
+  # kick off write
+  (ata-drive-select 0xf0)  # primary bus, secondary drive; 4 LSBs contain 4 upper bits of LBA (here 0)
+  (clear-ata-error)
+  (ata-sector-count 1)
+  (ata-lba 0 0 0)  # lower 24 bits of LBA, all 0
+  (ata-command 0x30)  # write sectors with retries
+  # wait
+  (while-ata-busy)
+  (until-ata-ready-for-data)
+  # send data
+  ba/copy-to-edx 0x1f0/imm32
+  b9/copy-to-ecx 0x200/imm32  # 512 bytes per sector
+  # var first-byte/ebx: byte
+  # when it's more than 0xff, we're at an even-numbered byte
+  bb/copy-to-ebx 0xffff/imm32
+$store-first-sector-to-primary-bus-secondary-drive:loop:
+  {
+    81 7/subop/compare %ecx 0/imm32
+    74/jump-if-= break/disp8
+    # this loop is slow, but the ATA spec also requires a small delay
+    (stream-empty? *(ebp+8))  # => eax
+    3d/compare-eax-and 0/imm32/false
+    75/jump-if-!= break/disp8
+    # read byte from stream
+    (read-byte *(ebp+8))  # => eax
+    # if we're at an odd-numbered byte, save it to first-byte
+    81 7/subop/compare %ebx 0xff/imm32
+    {
+      7e/jump-if-<= break/disp8
+      89/<- %ebx 0/r32/eax
+      eb/jump $store-first-sector-to-primary-bus-secondary-drive:loop/disp8
+    }
+    # otherwise OR it with first-byte and write it out
+    c1/shift 4/subop/left %eax 8/imm8
+    09/or %eax 3/r32/ebx
+    66 ef/write-ax-into-port-dx
+    49/decrement-ecx
+    49/decrement-ecx
+    # reset first-byte
+    bb/copy-to-ebx 0xffff/imm32
+    eb/jump loop/disp8
+  }
+  # write out first-byte if necessary
+  81 7/subop/compare %ebx 0xff/imm32
+  {
+    7f/jump-if-> break/disp8
+    89/<- %eax 3/r32/ebx
+    66 ef/write-ax-into-port-dx
+    49/decrement-ecx
+    49/decrement-ecx
+  }
+  # pad zeroes
+  31/xor %eax 0/r32/eax
+  {
+    81 7/subop/compare %ecx 0/imm32
+    74/jump-if-= break/disp8
+    66 ef/write-ax-into-port-dx
+    49/decrement-ecx
+    49/decrement-ecx
+    eb/jump loop/disp8
+  }
+$store-first-sector-to-primary-bus-secondary-drive:end:
+  # . restore registers
+  5b/pop-to-ebx
+  5a/pop-to-edx
+  59/pop-to-ecx
+  58/pop-to-eax
+  # . epilogue
+  89/<- %esp 5/r32/ebp
+  5d/pop-to-ebp
+  c3/return
+
 secondary-drive-exists?:  # -> _/eax: boolean
   # . prologue
   55/push-ebp
@@ -1205,4 +1290,8 @@ $while-ata-busy:end:
   # . epilogue
   c3/return
 
+until-ata-ready-for-data:
+  (until-ata-data-available)
+  c3/return
+
 # vim:ft=subx
diff --git a/shell/sandbox.mu b/shell/sandbox.mu
index 46dc21f1..5278e708 100644
--- a/shell/sandbox.mu
+++ b/shell/sandbox.mu
@@ -130,6 +130,9 @@ fn edit-sandbox _self: (addr sandbox), key: byte {
     var trace/eax: (addr trace) <- lookup *trace-ah
     clear-trace trace
     run data, value, trace
+    # testing write to disk
+#?     rewind-stream value
+#?     store-first-sector-to-primary-bus-secondary-drive value
     return
   }
   # tab
06 +0200 hotfix for 32bit unsigned 'range' checking; incomplete, unknown why some operations produce range checks' href='/ahoang/Nim/commit/lib/system/chcks.nim?h=devel&id=84ca1f3bf3d0095034973fae8c36999f8778c451'>84ca1f3bf ^
52851b722 ^




7894f50a5 ^
52851b722 ^
fc0fda14a ^
52851b722 ^


1268ca79e ^




52851b722 ^
2ab6b2c65 ^












































8bb1a6b04 ^




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

 
                                  






                                                   
                          
 
                                                                  
                              
                                              
       
                                                      
 





                                                                
                                                   
                                             
 
                                                            
                                               




                                  
                             












                                                          





                                                           




                                        
                                                
         
                                                      


                          




                                                                  
 












































                                                                                




                                                                                    
#
#
#            Nim's Runtime Library
#        (c) Copyright 2013 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# Implementation of some runtime checks.
include system/indexerrors

proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
  when hostOS == "standalone":
    sysFatal(RangeError, "value out of range")
  else:
    sysFatal(RangeError, "value out of range: ", $val)

proc raiseIndexError3(i, a, b: int) {.compilerproc, noinline.} =
  sysFatal(IndexError, formatErrorIndexBound(i, a, b))

proc raiseIndexError2(i, n: int) {.compilerproc, noinline.} =
  sysFatal(IndexError, formatErrorIndexBound(i, n))

proc raiseIndexError() {.compilerproc, noinline.} =
  sysFatal(IndexError, "index out of bounds")

proc raiseFieldError(f: string) {.compilerproc, noinline.} =
  sysFatal(FieldError, f, " is not accessible")

proc chckIndx(i, a, b: int): int =
  if i >= a and i <= b:
    return i
  else:
    raiseIndexError3(i, a, b)

proc chckRange(i, a, b: int): int =
  if i >= a and i <= b:
    return i
  else:
    raiseRangeError(i)

proc chckRange64(i, a, b: int64): int64 {.compilerproc.} =
  if i >= a and i <= b:
    return i
  else:
    raiseRangeError(i)

proc chckRangeU(i, a, b: uint64): uint64 {.compilerproc.} =
  if i >= a and i <= b:
    return i
  else:
    sysFatal(RangeError, "value out of range")

proc chckRangeF(x, a, b: float): float =
  if x >= a and x <= b:
    return x
  else:
    when hostOS == "standalone":
      sysFatal(RangeError, "value out of range")
    else:
      sysFatal(RangeError, "value out of range: ", $x)

proc chckNil(p: pointer) =
  if p == nil:
    sysFatal(NilAccessError, "attempt to write to a nil address")

proc chckNilDisp(p: pointer) {.compilerproc.} =
  if p == nil:
    sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")

when not defined(nimV2):

  proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
    # checks if obj is of type subclass:
    var x = obj
    if x == subclass: return # optimized fast path
    while x != subclass:
      if x == nil:
        sysFatal(ObjectConversionError, "invalid object conversion")
      x = x.base

  proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} =
    if a != b:
      sysFatal(ObjectAssignmentError, "invalid object assignment")

  type ObjCheckCache = array[0..1, PNimType]

  proc isObjSlowPath(obj, subclass: PNimType;
                    cache: var ObjCheckCache): bool {.noinline.} =
    # checks if obj is of type subclass:
    var x = obj.base
    while x != subclass:
      if x == nil:
        cache[0] = obj
        return false
      x = x.base
    cache[1] = obj
    return true

  proc isObjWithCache(obj, subclass: PNimType;
                      cache: var ObjCheckCache): bool {.compilerProc, inline.} =
    if obj == subclass: return true
    if obj.base == subclass: return true
    if cache[0] == obj: return false
    if cache[1] == obj: return true
    return isObjSlowPath(obj, subclass, cache)

  proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
    # checks if obj is of type subclass:
    var x = obj
    if x == subclass: return true # optimized fast path
    while x != subclass:
      if x == nil: return false
      x = x.base
    return true

when defined(nimV2):
  proc nimFieldDiscriminantCheckV2(oldDiscVal, newDiscVal: uint8) {.compilerProc.} =
    if oldDiscVal != newDiscVal:
      sysFatal(FieldError, "assignment to discriminant changes object branch")