1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
//! Hikari - Program loader
const afs = @import("../fs/afs/afs.zig");
const ahci = @import("../drivers/ahci/ahci.zig");
const elf = @import("elf/elf.zig");
const elf_const = @import("../common/constants/elf.zig");
const format = @import("format/format.zig");
const gdt = @import("../boot/gdt/gdt.zig");
const heap = @import("../memory/heap.zig");
const kata_const = @import("../common/constants/kata.zig");
const kata_limits = @import("../common/limits/kata.zig");
const kata_memory = @import("../kata/memory.zig");
const kata_mod = @import("../kata/kata.zig");
const memory_const = @import("../common/constants/memory.zig");
const multiboot = @import("../boot/multiboot/multiboot.zig");
const paging = @import("../memory/paging.zig");
const sensei = @import("../kata/sensei/sensei.zig");
const serial = @import("../drivers/serial/serial.zig");
const fs_limits = @import("../common/limits/fs.zig");
const INIT_LOCATION = "/system/akiba/pulse.gen";
pub fn init(fs: *afs.AFS(ahci.BlockDevice)) !u32 {
const init_size = fs.get_unit_size(INIT_LOCATION) catch |err| {
serial.print("FATAL: Cannot find init at ");
serial.print(INIT_LOCATION);
serial.print("\n");
return err;
};
if (init_size == 0) {
serial.print("FATAL: Init is empty\n");
return error.EmptyUnit;
}
var args: [1][]const u8 = .{INIT_LOCATION};
return load_with_args(fs, INIT_LOCATION, &args);
}
pub fn load(fs: *afs.AFS(ahci.BlockDevice), location: []const u8) !u32 {
var args: [1][]const u8 = .{location};
return load_with_args(fs, location, &args);
}
pub fn load_with_args(
fs: *afs.AFS(ahci.BlockDevice),
location: []const u8,
args: []const []const u8,
) !u32 {
if (location.len == 0 or location.len > fs_limits.MAX_LOCATION_LENGTH) {
return error.InvalidLocation;
}
const unit_size = try fs.get_unit_size(location);
if (unit_size == 0) return error.EmptyUnit;
if (unit_size > fs_limits.MAX_UNIT_SIZE) return error.UnitTooLarge;
const buffer_ptr = heap.alloc(@intCast(unit_size)) orelse return error.OutOfMemory;
defer heap.free(buffer_ptr, @intCast(unit_size));
const buffer = buffer_ptr[0..@intCast(unit_size)];
const bytes_read = try fs.view_unit_at(location, buffer);
if (bytes_read != unit_size) {
return error.IncompleteRead;
}
const akiba_data = try format.parse(buffer[0..bytes_read]);
const elf_info = try elf.parse(akiba_data.elf_data);
const kata = try kata_mod.create_kata();
errdefer kata_mod.dissolve_kata(kata.id);
if (sensei.get_current_kata()) |parent| {
kata.parent_id = parent.id;
for (0..parent.current_location_len) |i| {
kata.current_location[i] = parent.current_location[i];
}
kata.current_location_len = parent.current_location_len;
kata.current_cluster = parent.current_cluster;
}
const fb_info = multiboot.get_framebuffer();
const fb_phys = if (fb_info) |fb| fb.addr else 0;
const fb_size = if (fb_info) |fb| fb.height * fb.pitch else 0;
try kata_memory.setup(kata, fb_phys, fb_size);
for (elf_info.program_headers) |phdr| {
if (phdr.type == elf_const.PT_LOAD) {
try kata_memory.load_segment(
kata,
phdr.vaddr,
akiba_data.elf_data,
phdr.offset,
phdr.filesz,
phdr.memsz,
phdr.flags,
);
}
}
const adjusted_stack = try setup_stack_args(kata, args);
setup_context(kata, elf_info.entry_point, adjusted_stack);
sensei.enqueue_kata(kata);
return kata.id;
}
fn setup_stack_args(kata: *kata_mod.Kata, args: []const []const u8) !u64 {
var stack_top = kata.user_stack_top;
const pc: u64 = args.len;
var string_addrs: [kata_limits.MAX_PARAMETERS]u64 = undefined;
for (args, 0..) |arg, i| {
const str_len = arg.len + 1;
stack_top -= str_len;
stack_top &= ~@as(u64, 0x7);
string_addrs[i] = stack_top;
const phys_addr = paging.virt_to_phys(kata.page_table, stack_top) orelse return error.StackNotMapped;
const dest = @as([*]u8, @ptrFromInt(phys_addr + memory_const.HIGHER_HALF_START));
for (arg, 0..) |c, j| {
dest[j] = c;
}
dest[arg.len] = 0;
}
const pv_size = pc * 8;
stack_top -= pv_size;
stack_top &= ~@as(u64, 0x7);
const pv_addr = stack_top;
for (0..pc) |i| {
const ptr_phys = paging.virt_to_phys(kata.page_table, pv_addr + i * 8) orelse return error.StackNotMapped;
const ptr_dest = @as(*u64, @ptrFromInt(ptr_phys + memory_const.HIGHER_HALF_START));
ptr_dest.* = string_addrs[i];
}
stack_top &= ~@as(u64, 0xF);
stack_top -= 8;
const pv_ptr_phys = paging.virt_to_phys(kata.page_table, stack_top) orelse return error.StackNotMapped;
@as(*u64, @ptrFromInt(pv_ptr_phys + memory_const.HIGHER_HALF_START)).* = pv_addr;
stack_top -= 8;
const pc_phys = paging.virt_to_phys(kata.page_table, stack_top) orelse return error.StackNotMapped;
@as(*u64, @ptrFromInt(pc_phys + memory_const.HIGHER_HALF_START)).* = pc;
return stack_top;
}
fn setup_context(kata: *kata_mod.Kata, entry_point: u64, stack_pointer: u64) void {
kata.context.rip = entry_point;
kata.context.rsp = stack_pointer;
kata.context.rflags = kata_const.USER_RFLAGS;
kata.context.cs = gdt.USER_CODE | 3;
kata.context.ss = gdt.USER_DATA | 3;
kata.context.rax = 0;
kata.context.rbx = 0;
kata.context.rcx = 0;
kata.context.rdx = 0;
kata.context.rsi = 0;
kata.context.rdi = 0;
kata.context.rbp = 0;
kata.context.r8 = 0;
kata.context.r9 = 0;
kata.context.r10 = 0;
kata.context.r11 = 0;
kata.context.r12 = 0;
kata.context.r13 = 0;
kata.context.r14 = 0;
kata.context.r15 = 0;
}
|