build-the-world.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. #!/usr/bin/python3
  2. import tarfile
  3. import glob
  4. import subprocess
  5. import array
  6. import struct
  7. import os
  8. def BuildKernel():
  9. kernel_c_sources = glob.glob("kernel/*.c") + glob.glob("kernel/*/*.c") + glob.glob("kernel/*/*/*.c")
  10. kernel_s_sources = glob.glob("kernel/*.S")
  11. cflags = "-O2 -std=c99 -finline-functions -ffreestanding -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format -pedantic -fno-omit-frame-pointer -D_KERNEL_ -DKERNEL_GIT_TAG=master"
  12. for i in kernel_c_sources:
  13. cmd = "gcc {cflags} -nostdlib -g -c -o {obj} {src}".format(
  14. cflags=cflags,
  15. obj=i.replace('.c','.o'),
  16. src=i
  17. )
  18. print(cmd)
  19. subprocess.run(cmd, shell=True)
  20. for i in kernel_s_sources:
  21. cmd = "as -o {obj} {src}".format(
  22. obj=i.replace('.S','.o'),
  23. src=i
  24. )
  25. print(cmd)
  26. subprocess.run(cmd,shell=True)
  27. objects = [x.replace('.c','.o') for x in kernel_c_sources] + [x.replace('.S','.o') for x in kernel_s_sources if not x.endswith('symbols.S')]
  28. cmd = "gcc -T kernel/link.ld {cflags} -nostdlib -o .toaruos-kernel {objects} -lgcc".format(
  29. cflags=cflags,
  30. objects=' '.join(objects),
  31. )
  32. print(cmd)
  33. subprocess.run(cmd, shell=True)
  34. cmd = "nm -g .toaruos-kernel | generate_symbols.py > kernel/symbols.S"
  35. print(cmd)
  36. subprocess.run(cmd,shell=True)
  37. subprocess.run("rm .toaruos-kernel", shell=True)
  38. cmd = "as -o kernel/symbols.o kernel/symbols.S"
  39. print(cmd)
  40. subprocess.run(cmd,shell=True)
  41. cmd = "gcc -T kernel/link.ld {cflags} -nostdlib -o cdrom/kernel {objects} kernel/symbols.o -lgcc".format(
  42. cflags=cflags,
  43. objects=' '.join(objects),
  44. )
  45. print(cmd)
  46. subprocess.run(cmd, shell=True)
  47. def BuildModules():
  48. module_sources = glob.glob('modules/*.c')
  49. cflags = "-O2 -std=c99 -finline-functions -ffreestanding -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format -pedantic -fno-omit-frame-pointer -D_KERNEL_ -DKERNEL_GIT_TAG=master"
  50. try:
  51. os.mkdir('cdrom/mod')
  52. except:
  53. pass
  54. for i in module_sources:
  55. cmd = "gcc {cflags} -nostdlib -g -c -o {obj} {src}".format(
  56. cflags=cflags,
  57. obj=i.replace('.c','.ko').replace('modules/','cdrom/mod/'),
  58. src=i
  59. )
  60. print(cmd)
  61. subprocess.run(cmd, shell=True)
  62. class Structure(object):
  63. assert_size = -1
  64. def __init__(self):
  65. self.data = {}
  66. for field in self.fields:
  67. if len(field) > 2:
  68. f, s, d = field
  69. self.data[s] = d
  70. else:
  71. f, s = field
  72. if f.endswith('s'):
  73. self.data[s] = b""
  74. else:
  75. self.data[s] = 0
  76. if self.assert_size != -1:
  77. assert(len(self) == self.assert_size)
  78. def __len__(self):
  79. return sum([struct.calcsize(f[0]) for f in self.fields])
  80. def read(self, data, offset):
  81. def read_struct(fmt,buf,offset):
  82. out, = struct.unpack_from(fmt,buf,offset)
  83. return out, offset + struct.calcsize(fmt)
  84. o = offset
  85. for field in self.fields:
  86. if len(field) > 2:
  87. f, s, _ = field
  88. else:
  89. f, s = field
  90. self.data[s], o = read_struct(f, data, o)
  91. return o
  92. def write(self, data, offset):
  93. def write_struct(fmt, buf, offset, value):
  94. struct.pack_into(fmt, buf, offset, value)
  95. return offset + struct.calcsize(fmt)
  96. o = offset
  97. for field in self.fields:
  98. if len(field) > 2:
  99. f, s, _ = field
  100. else:
  101. f, s = field
  102. o = write_struct(f,data,o,self.data[s])
  103. return o
  104. def read_struct(fmt,buf,offset):
  105. out, = struct.unpack_from(fmt,buf,offset)
  106. return out, offset + struct.calcsize(fmt)
  107. class FAT(object):
  108. def __init__(self, iso, offset):
  109. self.iso = iso
  110. self.offset = offset
  111. self.bytespersector, _ = read_struct('H', self.iso.data, offset + 11)
  112. self.sectorspercluster, _ = read_struct('B', self.iso.data, offset + 13)
  113. self.reservedsectors, _ = read_struct('H', self.iso.data, offset + 14)
  114. self.numberoffats, _ = read_struct('B', self.iso.data, offset + 16)
  115. self.numberofdirs, _ = read_struct('H', self.iso.data, offset + 17)
  116. self.fatsize, _ = read_struct('H', self.iso.data, offset + 22)
  117. self.root_dir_sectors = (self.numberofdirs * 32 + (self.bytespersector - 1)) // self.bytespersector
  118. self.first_data_sector = self.reservedsectors + (self.numberoffats * self.fatsize) + self.root_dir_sectors
  119. self.root_sector= self.first_data_sector - self.root_dir_sectors
  120. self.root = FATDirectory(self, self.offset + self.root_sector * self.bytespersector)
  121. def get_offset(self, cluster):
  122. return self.offset + ((cluster - 2) * self.sectorspercluster + self.first_data_sector) * self.bytespersector
  123. def get_file(self, path):
  124. units = path.split('/')
  125. units = units[1:]
  126. me = self.root
  127. out = None
  128. for i in units:
  129. for fatfile in me.list():
  130. if fatfile.readable_name() == i:
  131. me = fatfile.to_dir()
  132. out = fatfile
  133. break
  134. else:
  135. return None
  136. return out
  137. class FATDirectory(object):
  138. def __init__(self, fat, offset):
  139. self.fat = fat
  140. self.offset = offset
  141. def list(self):
  142. o = self.offset
  143. while 1:
  144. out = FATFile(self.fat, o)
  145. if out.name != '\0\0\0\0\0\0\0\0':
  146. yield out
  147. else:
  148. break
  149. o += out.size
  150. class FATFile(object):
  151. def __init__(self, fat, offset):
  152. self.fat = fat
  153. self.offset = offset
  154. self.magic_long = None
  155. self.size = 0
  156. self.long_name = ''
  157. o = self.offset
  158. self.actual_offset = o
  159. self.attrib, _ = read_struct('B',self.fat.iso.data,o+11)
  160. while (self.attrib & 0x0F) == 0x0F:
  161. # Long file name entry
  162. tmp = read_struct('10s',self.fat.iso.data,o+1)[0]
  163. tmp += read_struct('12s',self.fat.iso.data,o+14)[0]
  164. tmp += read_struct('4s',self.fat.iso.data,o+28)[0]
  165. tmp = "".join([chr(x) for x in tmp[::2] if x != '\xFF']).strip('\x00')
  166. self.long_name = tmp + self.long_name
  167. self.size += 32
  168. o = self.offset + self.size
  169. self.actual_offset = o
  170. self.attrib, _ = read_struct('B',self.fat.iso.data,o+11)
  171. o = self.offset + self.size
  172. self.name, o = read_struct('8s',self.fat.iso.data,o)
  173. self.ext, o = read_struct('3s',self.fat.iso.data,o)
  174. self.attrib, o = read_struct('B',self.fat.iso.data,o)
  175. self.userattrib, o = read_struct('B',self.fat.iso.data,o)
  176. self.undelete, o = read_struct('b',self.fat.iso.data,o)
  177. self.createtime, o = read_struct('H',self.fat.iso.data,o)
  178. self.createdate, o = read_struct('H',self.fat.iso.data,o)
  179. self.accessdate, o = read_struct('H',self.fat.iso.data,o)
  180. self.clusterhi, o = read_struct('H',self.fat.iso.data,o)
  181. self.modifiedti, o = read_struct('H',self.fat.iso.data,o)
  182. self.modifiedda, o = read_struct('H',self.fat.iso.data,o)
  183. self.clusterlow, o = read_struct('H',self.fat.iso.data,o)
  184. self.filesize, o = read_struct('I',self.fat.iso.data,o)
  185. self.name = self.name.decode('ascii')
  186. self.ext = self.ext.decode('ascii')
  187. self.size += 32
  188. self.cluster = (self.clusterhi << 16) + self.clusterlow
  189. def is_dir(self):
  190. return bool(self.attrib & 0x10)
  191. def is_long(self):
  192. return bool((self.attrib & 0x0F) == 0x0F)
  193. def to_dir(self):
  194. return FATDirectory(self.fat, self.fat.get_offset(self.cluster))
  195. def get_offset(self):
  196. return self.fat.get_offset(self.cluster)
  197. def readable_name(self):
  198. if self.long_name:
  199. return self.long_name
  200. if self.ext.strip():
  201. return (self.name.strip() + '.' + self.ext.strip()).lower()
  202. else:
  203. return self.name.strip().lower()
  204. def make_time():
  205. data = array.array('b',b'\0'*17)
  206. struct.pack_into(
  207. '4s2s2s2s2s2s2sb',
  208. data, 0,
  209. b'2018', b'11', b'14', # Year, Month, Day
  210. b'12', b'00', b'00', # Hour, Minute, Second
  211. b'00', # Hundreths
  212. 0, # Offset
  213. )
  214. return bytes(data)
  215. def make_date():
  216. data = array.array('b',b'\0'*7)
  217. struct.pack_into(
  218. 'BBBBBBb',
  219. data, 0,
  220. 118, 11, 14,
  221. 12, 0, 0,
  222. 0,
  223. )
  224. return bytes(data)
  225. class ISOBootRecord(Structure):
  226. assert_size = 2048
  227. fields = (
  228. ('B', 'type_code', 0),
  229. ('5s', 'cd001', b'CD001'),
  230. ('B', 'version', 1),
  231. ('32s', 'boot_system_identifier'),
  232. ('32s', 'boot_identifier'),
  233. ('1977s', 'boot_record_data'),
  234. )
  235. class ISOElToritoBootRecord(ISOBootRecord):
  236. assert_size = 2048
  237. fields = (
  238. ('B', 'type_code', 0),
  239. ('5s', 'cd001', b'CD001'),
  240. ('B', 'version', 1),
  241. ('32s', 'boot_system_identifier',b'EL TORITO SPECIFICATION'),
  242. ('32s', 'boot_identifier'),
  243. ('<I', 'catalog_lba'),
  244. ('1973s', 'boot_record_data'),
  245. )
  246. def set_catalog(self, catalog_lba):
  247. self.data['catalog_lba'] = catalog_lba
  248. class ISOPrimaryVolumeDescriptor(Structure):
  249. assert_size = 2048
  250. fields = (
  251. ('B', 'type_code', 1),
  252. ('5s', 'cd001', b'CD001'),
  253. ('B', 'version', 1),
  254. ('B', 'unused_0', 0),
  255. ('32s', 'system_id', b' '*32),
  256. ('32s', 'volume_id', b'ToaruOS Boot CD'.ljust(32)),
  257. ('8s', 'unused_1', b'\0'*8),
  258. ('<I', 'volume_space_lsb'),
  259. ('>I', 'volume_space_msb'),
  260. ('32s', 'unused_2', b'\0'*32),
  261. ('<H', 'volume_set_size_lsb', 1),
  262. ('>H', 'volume_set_size_msb', 1),
  263. ('<H', 'volume_sequence_lsb', 1),
  264. ('>H', 'volume_sequence_msb', 1),
  265. ('<H', 'logical_block_size_lsb', 2048),
  266. ('>H', 'logical_block_size_msb', 2048),
  267. ('<I', 'path_table_size_lsb'),
  268. ('>I', 'path_table_size_msb'),
  269. ('<I', 'type_l_table_lsb'),
  270. ('<I', 'optional_type_l_table_lsb'),
  271. ('>I', 'type_m_table_msb'),
  272. ('>I', 'optional_type_m_table_msb'),
  273. ('34s', 'root_entry_data'),
  274. ('128s', 'volume_set_identifier', b' '*128),
  275. ('128s', 'publisher_identifier', b' '*128),
  276. ('128s', 'data_preparer_identifier', b' '*128),
  277. ('128s', 'application_identifier',b' '*128),
  278. ('38s', 'copyright_file_identifier',b' '*38),
  279. ('36s', 'abstract_file_identifier',b' '*36),
  280. ('37s', 'bibliographic_file_identifier',b' '*37),
  281. ('17s', 'volume_creation_time',make_time()),
  282. ('17s', 'volume_modification_time',make_time()),
  283. ('17s', 'volume_expiration_time',make_time()),
  284. ('17s', 'volume_effective_time',make_time()),
  285. ('B', 'file_structure_version'),
  286. ('B', 'unused_3', 0),
  287. ('512s', 'application_data'),
  288. ('653s', 'reserved', b'\0'*653),
  289. )
  290. class ISOVolumeDescriptorSetTerminator(Structure):
  291. assert_size = 2048
  292. fields = (
  293. ('B', 'type_code', 0xFF),
  294. ('5s', 'cd001', b'CD001'),
  295. ('B', 'version', 1),
  296. ('2041s', 'unused', b'\0'*2041)
  297. )
  298. class ISODirectoryEntry(Structure):
  299. assert_size = 33
  300. fields = (
  301. ('B', 'length'),
  302. ('B', 'ext_length'),
  303. ('<I', 'extent_start_lsb'),
  304. ('>I', 'extent_start_msb'),
  305. ('<I', 'extent_length_lsb'),
  306. ('>I', 'extent_length_msb'),
  307. ('7s', 'record_date', make_date()),
  308. ('B', 'flags'),
  309. ('B', 'interleave_units'),
  310. ('B', 'interleave_gap'),
  311. ('<H', 'volume_seq_lsb'),
  312. ('>H', 'volume_seq_msb'),
  313. ('B', 'name_len'),
  314. )
  315. def set_name(self, name):
  316. self.data['name_len'] = len(name)
  317. self.name = name
  318. self.data['length'] = self.assert_size + len(self.name)
  319. if self.data['length'] % 2:
  320. self.data['length'] += 1
  321. def set_extent(self, start, length):
  322. self.data['extent_start_lsb'] = start
  323. self.data['extent_start_msb'] = start
  324. self.data['extent_length_lsb'] = length
  325. self.data['extent_length_msb'] = length
  326. def write(self, data, offset):
  327. o = super(ISODirectoryEntry,self).write(data,offset)
  328. struct.pack_into(str(len(self.name))+'s', data, o, self.name.encode('utf-8'))
  329. return offset + self.data['length']
  330. class ArbitraryData(object):
  331. def __init__(self, path=None, size=None):
  332. if path:
  333. with open(path,'rb') as f:
  334. tmp = f.read()
  335. self.data = array.array('b',tmp)
  336. elif size:
  337. self.data = array.array('b',b'\0'*size)
  338. else:
  339. raise ValueError("Expected one of path or size to be set.")
  340. self.size = len(self.data.tobytes())
  341. self.actual_size = self.size
  342. while (self.size % 2048):
  343. self.size += 1
  344. def write(self, data, offset):
  345. struct.pack_into(str(self.size) + 's', data, offset, self.data.tobytes())
  346. return offset + self.size
  347. def make_entry():
  348. return b'\0'*34
  349. class ISO9660(object):
  350. def __init__(self, from_file=None):
  351. self.primary_volume_descriptor = ISOPrimaryVolumeDescriptor()
  352. self.boot_record = ISOElToritoBootRecord()
  353. self.volume_descriptor_set_terminator = ISOVolumeDescriptorSetTerminator()
  354. self.el_torito_catalog = ElToritoCatalog()
  355. self.allocate = 0x13
  356. if from_file:
  357. # Only for a file we produced.
  358. with open(from_file, 'rb') as f:
  359. tmp = f.read()
  360. data = array.array('b', tmp)
  361. self.primary_volume_descriptor.read(data, 0x10 * 2048)
  362. self.boot_record.read(data, 0x11 * 2048)
  363. self.volume_descriptor_set_terminator.read(data, 0x12 * 2048)
  364. self.el_torito_catalog.read(data, self.boot_record.data['catalog_lba'] * 2048)
  365. else:
  366. # Root directory
  367. self.root = ISODirectoryEntry()
  368. self.root.data['flags'] = 0x02 # Directory
  369. self.root.set_name(' ')
  370. self.root_data = ArbitraryData(size=2048)
  371. self.root_data.sector_offset = self.allocate_space(1)
  372. self.root.set_extent(self.root_data.sector_offset,self.root_data.size)
  373. # Dummy entries
  374. t = ISODirectoryEntry()
  375. t.set_name('')
  376. o = t.write(self.root_data.data, 0)
  377. t = ISODirectoryEntry()
  378. t.set_name('\1')
  379. o = t.write(self.root_data.data, o)
  380. # Kernel
  381. self.kernel_data = ArbitraryData(path='cdrom/kernel')
  382. self.kernel_data.sector_offset = self.allocate_space(self.kernel_data.size // 2048)
  383. self.kernel_entry = ISODirectoryEntry()
  384. self.kernel_entry.set_name('KERNEL.')
  385. self.kernel_entry.set_extent(self.kernel_data.sector_offset, self.kernel_data.actual_size)
  386. o = self.kernel_entry.write(self.root_data.data, o)
  387. # Ramdisk
  388. self.ramdisk_data = ArbitraryData(path='cdrom/ramdisk.img')
  389. self.ramdisk_data.sector_offset = self.allocate_space(self.ramdisk_data.size // 2048)
  390. self.ramdisk_entry = ISODirectoryEntry()
  391. self.ramdisk_entry.set_name('RAMDISK.IMG')
  392. self.ramdisk_entry.set_extent(self.ramdisk_data.sector_offset, self.ramdisk_data.actual_size)
  393. o = self.ramdisk_entry.write(self.root_data.data, o)
  394. # Modules directory
  395. self.mods_data = ArbitraryData(size=(2048*2)) # Just in case
  396. self.mods_data.sector_offset = self.allocate_space(self.mods_data.size // 2048)
  397. self.mods_entry = ISODirectoryEntry()
  398. self.mods_entry.data['flags'] = 0x02
  399. self.mods_entry.set_name('MOD')
  400. self.mods_entry.set_extent(self.mods_data.sector_offset, self.mods_data.actual_size)
  401. o = self.mods_entry.write(self.root_data.data, o)
  402. self.payloads = []
  403. # Modules themselves
  404. t = ISODirectoryEntry()
  405. t.set_name('')
  406. o = t.write(self.mods_data.data, 0)
  407. t = ISODirectoryEntry()
  408. t.set_name('\1')
  409. o = t.write(self.mods_data.data, o)
  410. for mod_file in [
  411. 'cdrom/mod/ac97.ko',
  412. 'cdrom/mod/ata.ko',
  413. 'cdrom/mod/ataold.ko',
  414. 'cdrom/mod/debug_sh.ko',
  415. 'cdrom/mod/dospart.ko',
  416. 'cdrom/mod/e1000.ko',
  417. 'cdrom/mod/ext2.ko',
  418. 'cdrom/mod/hda.ko',
  419. 'cdrom/mod/iso9660.ko',
  420. 'cdrom/mod/lfbvideo.ko',
  421. 'cdrom/mod/net.ko',
  422. 'cdrom/mod/packetfs.ko',
  423. 'cdrom/mod/pcnet.ko',
  424. 'cdrom/mod/pcspkr.ko',
  425. 'cdrom/mod/portio.ko',
  426. 'cdrom/mod/procfs.ko',
  427. 'cdrom/mod/ps2kbd.ko',
  428. 'cdrom/mod/ps2mouse.ko',
  429. 'cdrom/mod/random.ko',
  430. 'cdrom/mod/rtl.ko',
  431. 'cdrom/mod/serial.ko',
  432. 'cdrom/mod/snd.ko',
  433. 'cdrom/mod/tmpfs.ko',
  434. 'cdrom/mod/usbuhci.ko',
  435. 'cdrom/mod/vbox.ko',
  436. 'cdrom/mod/vgadbg.ko',
  437. 'cdrom/mod/vgalog.ko',
  438. 'cdrom/mod/vidset.ko',
  439. 'cdrom/mod/vmware.ko',
  440. 'cdrom/mod/xtest.ko',
  441. 'cdrom/mod/zero.ko',
  442. 'cdrom/mod/tarfs.ko',
  443. ]:
  444. payload = ArbitraryData(path=mod_file)
  445. payload.sector_offset = self.allocate_space(payload.size // 2048)
  446. entry = ISODirectoryEntry()
  447. entry.set_name(mod_file.replace('cdrom/mod/','').upper())
  448. entry.set_extent(payload.sector_offset, payload.actual_size)
  449. o = entry.write(self.mods_data.data, o)
  450. self.payloads.append(payload)
  451. # Set up the boot catalog and records
  452. self.el_torito_catalog.sector_offset = self.allocate_space(1)
  453. self.boot_record.set_catalog(self.el_torito_catalog.sector_offset)
  454. self.boot_payload = ArbitraryData(path='cdrom/boot.sys')
  455. self.boot_payload.sector_offset = self.allocate_space(self.boot_payload.size // 2048)
  456. self.el_torito_catalog.initial_entry.data['sector_count'] = self.boot_payload.size // 512
  457. self.el_torito_catalog.initial_entry.data['load_rba'] = self.boot_payload.sector_offset
  458. #self.el_torito_catalog.section.data['sector_count'] = 0 # Expected to be 0 or 1 for "until end of CD"
  459. #self.el_torito_catalog.section.data['load_rba'] = self.fat_payload.sector_offset
  460. self.primary_volume_descriptor.data['root_entry_data'] = make_entry()
  461. def allocate_space(self, sectors):
  462. out = self.allocate
  463. self.allocate += sectors
  464. return out
  465. def write(self, file_name):
  466. with open(file_name, 'wb') as f:
  467. data = array.array('b',b'\0'*(2048*self.allocate))
  468. self.primary_volume_descriptor.write(data,0x10 * 2048)
  469. self.root.write(data,0x10*2048 + 156)
  470. self.boot_record.write(data,0x11 * 2048)
  471. self.mods_data.write(data, self.mods_data.sector_offset * 2048)
  472. self.root_data.write(data,self.root_data.sector_offset * 2048)
  473. self.volume_descriptor_set_terminator.write(data,0x12 * 2048)
  474. self.el_torito_catalog.write(data,self.el_torito_catalog.sector_offset * 2048)
  475. self.boot_payload.write(data,self.boot_payload.sector_offset * 2048)
  476. self.kernel_data.write(data,self.kernel_data.sector_offset * 2048)
  477. self.ramdisk_data.write(data,self.ramdisk_data.sector_offset * 2048)
  478. #self.fat_payload.write(data,self.fat_payload.sector_offset * 2048)
  479. for payload in self.payloads:
  480. payload.write(data,payload.sector_offset * 2048)
  481. data.tofile(f)
  482. class ElToritoValidationEntry(Structure):
  483. assert_size = 0x20
  484. fields = (
  485. ('B','header_id',1),
  486. ('B','platform_id',0),
  487. ('<H','reserved_0'),
  488. ('24s','id_str',b'\0'*24),
  489. ('<H','checksum',0x55aa),
  490. ('B','key_55',0x55),
  491. ('B','key_aa',0xaa),
  492. )
  493. class ElToritoInitialEntry(Structure):
  494. assert_size = 0x20
  495. fields = (
  496. ('B','bootable',0x88),
  497. ('B','media_type'),
  498. ('<H','load_segment'),
  499. ('B','system_type'),
  500. ('B','unused_0'),
  501. ('<H','sector_count'),
  502. ('<I','load_rba'),
  503. ('20s','unused_1',b'\0'*20),
  504. )
  505. class ElToritoSectionHeader(Structure):
  506. assert_size = 0x20
  507. fields = (
  508. ('B','header_id',0x91),
  509. ('B','platform_id',0xEF),
  510. ('<H','sections',1),
  511. ('28s','id_str',b'\0'*28)
  512. )
  513. class ElToritoSectionEntry(Structure):
  514. assert_size = 0x20
  515. fields = (
  516. ('B','bootable',0x88),
  517. ('B','media_type'),
  518. ('<H','load_segment'),
  519. ('B','system_type'),
  520. ('B','unused_0'),
  521. ('<H','sector_count'),
  522. ('<I','load_rba'),
  523. ('B','selection_criteria'),
  524. ('19s','vendor'),
  525. )
  526. class ElToritoCatalog(object):
  527. def __init__(self):
  528. self.validation_entry = ElToritoValidationEntry()
  529. self.initial_entry = ElToritoInitialEntry()
  530. self.section_header = ElToritoSectionHeader()
  531. self.section = ElToritoSectionEntry()
  532. def read(self, data, offset):
  533. o = offset
  534. o = self.validation_entry.read(data, o)
  535. o = self.initial_entry.read(data, o)
  536. o = self.section_header.read(data, o)
  537. o = self.section.read(data, o)
  538. def write(self, data, offset):
  539. o = offset
  540. o = self.validation_entry.write(data, o)
  541. o = self.initial_entry.write(data, o)
  542. o = self.section_header.write(data, o)
  543. o = self.section.write(data, o)
  544. def BuildISO():
  545. iso = ISO9660()
  546. iso.write('toaruos.iso')
  547. def BuildRamdisk():
  548. users = {
  549. 'root': 0,
  550. 'local': 1000,
  551. }
  552. restricted_files = {
  553. 'etc/master.passwd': 0o600,
  554. 'etc/sudoers': 0o600,
  555. 'tmp': 0o777,
  556. 'var': 0o755,
  557. 'bin/sudo': 0o4555,
  558. 'bin/gsudo': 0o4555,
  559. }
  560. def file_filter(tarinfo):
  561. # Root owns files by default.
  562. tarinfo.uid = 0
  563. tarinfo.gid = 0
  564. if tarinfo.name.startswith('home/'):
  565. # Home directory contents are owned by their users.
  566. user = tarinfo.name.split('/')[1]
  567. tarinfo.uid = users.get(user,0)
  568. tarinfo.gid = tarinfo.uid
  569. elif tarinfo.name in restricted_files:
  570. tarinfo.mode = restricted_files[tarinfo.name]
  571. if tarinfo.name.startswith('src'):
  572. # Let local own the files here
  573. tarinfo.uid = users.get('local')
  574. tarinfo.gid = tarinfo.uid
  575. # Skip object files
  576. if tarinfo.name.endswith('.so') or tarinfo.name.endswith('.o'):
  577. return None
  578. return tarinfo
  579. with tarfile.open('cdrom/ramdisk.img','w') as ramdisk:
  580. ramdisk.add('/',arcname='/',filter=file_filter,recursive=False) # Add a blank directory
  581. ramdisk.add('/',arcname='/usr',filter=file_filter,recursive=False) # Add a blank directory
  582. ramdisk.add('/usr/share',arcname='/usr/share',filter=file_filter)
  583. ramdisk.add('/',arcname='/usr/bin',filter=file_filter,recursive=False) # Add a blank directory
  584. ramdisk.add('/',arcname='/usr/lib',filter=file_filter,recursive=False) # Add a blank directory
  585. ramdisk.add('/usr/include',arcname='/usr/include',filter=file_filter)
  586. ramdisk.add('/',arcname='/dev',filter=file_filter,recursive=False) # Add a blank directory
  587. ramdisk.add('/',arcname='/cdrom',filter=file_filter,recursive=False) # Add a blank directory
  588. ramdisk.add('/etc',arcname='/etc',filter=file_filter)
  589. ramdisk.add('/',arcname='/var',filter=file_filter,recursive=False) # Add a blank directory
  590. ramdisk.add('/',arcname='/tmp',filter=file_filter,recursive=False) # Add a blank directory
  591. ramdisk.add('/',arcname='/proc',filter=file_filter,recursive=False) # Add a blank directory
  592. ramdisk.add('/home',arcname='/home',filter=file_filter)
  593. ramdisk.add('/opt',arcname='/opt',filter=file_filter)
  594. ramdisk.add('.lib',arcname='/lib',filter=file_filter)
  595. ramdisk.add('.bin',arcname='/bin',filter=file_filter)
  596. # Overrides
  597. ramdisk.add('/lib/libc.so',arcname='/lib/libc.so',filter=file_filter) # Need to build libc
  598. ramdisk.add('/lib/libm.so',arcname='/lib/libm.so',filter=file_filter)
  599. ramdisk.add('/lib/ld.so',arcname='/lib/ld.so',filter=file_filter) # Need to build linker
  600. ramdisk.add('.',arcname='/src',filter=file_filter,recursive=False) # Add a blank directory
  601. ramdisk.add('apps',arcname='/src/apps',filter=file_filter)
  602. ramdisk.add('kernel',arcname='/src/kernel',filter=file_filter)
  603. ramdisk.add('linker',arcname='/src/linker',filter=file_filter)
  604. ramdisk.add('lib',arcname='/src/lib',filter=file_filter)
  605. ramdisk.add('libc',arcname='/src/libc',filter=file_filter)
  606. ramdisk.add('boot',arcname='/src/boot',filter=file_filter)
  607. ramdisk.add('modules',arcname='/src/modules',filter=file_filter)
  608. ramdisk.add('/usr/bin/build-the-world.py',arcname='/usr/bin/build-the-world.py',filter=file_filter)
  609. def BuildLibraries():
  610. try:
  611. os.mkdir(".lib")
  612. except:
  613. pass # exists
  614. os.chdir(".lib")
  615. for lib in glob.glob("/src/lib/*.c"):
  616. cmd = "auto-dep.py --buildlib {lib}".format(lib=lib)
  617. print(cmd)
  618. subprocess.run(cmd,shell=True)
  619. os.chdir("/src")
  620. def BuildApps():
  621. try:
  622. os.mkdir(".bin")
  623. except:
  624. pass # exists
  625. os.chdir(".bin")
  626. for app in glob.glob("/src/apps/*.c"):
  627. cmd = "auto-dep.py --build {app}".format(app=app)
  628. print(cmd)
  629. subprocess.run(cmd,shell=True)
  630. for script in glob.glob("/src/apps/*.sh"):
  631. cmd = "cp {src} {dst} ; chmod +x {dst}".format(src=script,dst=script.replace("/src/apps/","/src/.bin/"))
  632. print(cmd)
  633. subprocess.run(cmd,shell=True)
  634. os.chdir("/src")
  635. def BuildBoot():
  636. def print_and_run(cmd):
  637. print(cmd)
  638. subprocess.run(cmd,shell=True)
  639. print_and_run("as -o boot/boot.o boot/boot.S")
  640. print_and_run("gcc -c -Os -o boot/cstuff.o boot/cstuff.c")
  641. print_and_run("ld -T boot/link.ld -o cdrom/boot.sys boot/boot.o boot/cstuff.o")
  642. if __name__ == '__main__':
  643. os.chdir("/src")
  644. try:
  645. os.mkdir('cdrom')
  646. except:
  647. pass
  648. print("Building the kernel...")
  649. BuildKernel()
  650. print("Building modules...")
  651. BuildModules()
  652. print("Building boot.sys...")
  653. BuildBoot()
  654. print("Building libraries...")
  655. BuildLibraries()
  656. print("Building applications...")
  657. BuildApps()
  658. print("Createing ramdisk...")
  659. BuildRamdisk()
  660. print("Building ISO...")
  661. BuildISO()